| Rev |
Age |
Author |
Path |
Log message |
Diff |
| 37636 |
11 h 20 m |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
refactor(cron): remove vendoritempricing one-offs; log catalog migration listing prices
- Remove migrateVendorItemPricing (2023 one-off) and its flag; fixOrders no longer reads vendoritempricing
- CatalogMigration sets listing prices via TagListingPriceService |
|
| 37631 |
15 h 27 m |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
feat(mail): wire inactive-recipient filter, clean addresses, remove attendance alerts
Wire MailRecipientFilter into both mail senders. Remove inactive hardcoded recipients, fix typo addresses, send market-share reminder to tech@. Delete sendAttendanceMorningAlert/EveningAlert, sendMailToHR and their CLI options. |
|
| 37617 |
1 d 23 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Undo an internal GRN so its invoice can be received again
A receipt taken before the serials were split left stock that cannot be corrected in place: a
serialised unit is held one to a row, so an invoice that should have created several rows created one,
and the rows that are missing cannot be added without also unpicking the running figures the receipt
moved. Reversing the receipt and taking it again through the same path is the only way to arrive at
what the invoice actually says.
The reversal removes what receiving created - the scans, the inventory units, the invoice items, the
purchase and the supplier invoice - and gives back the two running figures it moved: the warehouse
availability, and the quantity taken off the purchase order line. Both are worked out from the rows
being deleted rather than recomputed, so whatever the receipt added is exactly what comes off. A
purchase order the receipt closed is opened again. Availability is kept only as a running count with
nothing to rebuild it from, which is why it is adjusted by what is known to have been added rather
than by anything inferred.
An invoice whose stock has moved since is refused, not worked around. A unit that has been scanned out
or partly consumed is no longer the receipt's to remove, and deleting around it would leave the
warehouse holding stock that no record explains. Each invoice is reversed on its own so one refusal
leaves the rest untouched, and a dry run reports everything it would delete and every figure it would
change without writing.
Invoices are named explicitly rather than selected by date, so a reversal can only ever touch what it
was given. |
|
| 37613 |
2 d 1 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Receive internal transfer stock that was billed but never GRNed
Stock moved between our own warehouses is dispatched against an internal purchase order and
billed, but the destination warehouse still has to receive it by hand through the portal. Where
that never happened the units exist on an invoice and nowhere in inventory, and there is no way
to clear a backlog of them short of keying each invoice in again.
This adds a cron one-off that receives them. Per invoice it builds the rows the Excel GRN upload
would have carried and hands them to PurchaseOrderService.addPORowModels, which creates the
supplier invoice, the purchase and the inventory items in a single call, so none of receiving is
reimplemented here - the portal and this take the same path and can only ever agree.
It is deliberately narrow about what it will touch. Only INTERNAL buyers, because nothing should
be able to receive a partner's goods on their behalf. Only invoices with no supplier invoice
already recorded, so a repeat run skips what it has already done rather than receiving twice.
Only invoices resolving to a single purchase order, since addPORowModels resolves one order for
the whole map it is given and would otherwise attribute an invoice to the wrong one - for the
same reason each invoice is passed on its own. A serialized line whose serial number is missing
aborts its invoice instead of creating a unit no scan could ever match.
Each invoice commits or rolls back on its own, so one bad invoice cannot undo the ones already
received, and a dry run reports what it would receive without writing anything.
The receipt is recorded against the destination warehouse, which is what warehouse inventory is
keyed by. The buyer on the order is read only to confirm the store is internal; partner side
inventory is a separate receipt and is not touched. |
|
| 37602 |
3 d 13 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Remove no-op refreshSnapshotAgeing task; restore originalInventoryItemId backfill call
refreshSnapshotAgeing ran every 30 minutes aggregating warehouse.inventoryItem.rootInvoiceDate,
a column nothing ever wrote, so its UPDATE ... JOIN matched zero rows on every run and
currentinventorysnapshot.oldest_invoice_date was never populated on any of 11,686 rows.
Removed along with the sessionFactory field it was the only consumer of.
Application.java had migrations.migrateWarehouseOriginalInventoryItemId(batchSize) commented
out while still logging 'Starting migration...' and 'Migration completed.', so
--migrateOriginalInventoryItemId reported success while doing nothing. Restored the call;
it remains opt-in via the CLI flag and cannot fire on its own.
Requires profitmandi-dao r37601 (entity fields removed). |
|
| 37567 |
5 d 16 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Schedule the catalogue delist daily at 05:30
Runs 30 minutes before the existing 06:00 scheduledPushDataToSolr in the same
class, so the same morning's reindex publishes it. A bulk UPDATE fires no
TagListingChangeListener event, so without that ordering the portal would lag
until 18:00.
Gated on catalog.autoDelist.enabled with an inline default of true - env profiles
have no fallback between each other, so a key missing from one profile's
properties would otherwise stop the context booting.
Also exposes --delistDeadListings for a manual run, honouring the same flag. |
|
| 37510 |
14 d 10 h |
ranu |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
sales target and achievement added cron and flags |
|
| 37503 |
14 d 12 h |
ranu |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
sales target and achievement added cron and flags |
|
| 37499 |
14 d 12 h |
ranu |
/trunk/ |
sales target and achievement added cron and flags |
|
| 37480 |
15 d 10 h |
amit |
/trunk/ |
mail: correct a wrong claim in r37479 -- the Google app password IS valid
r37479 stated googleMailSender's app password was rejected. That was wrong. The
test behind it resolved smtp.gmail.com over IPv6; repeating it over IPv4 with
the same credential gives AUTH OK on both 465 and 587.
The real fault is not the credential and not the bean config, both of which are
correct. SMTP from this host works over IPv4 only:
smtp.gmail.com IPv4 -> AUTH OK IPv6 -> 535 5.7.8 Username and Password not accepted
smtp-relay IPv4 -> 250 MAIL FROM IPv6 -> 550 5.7.1 Invalid credentials for relay
The JVM prefers IPv4, which is the only reason mail leaves this box at all.
Anything that prefers IPv6 fails on both paths. |
|
| 37479 |
15 d 10 h |
amit |
/trunk/ |
mail: make the relay the default sender, not the Google identity
Correcting r37474-37476. Those made googleMailSender @Primary on the assumption
its credentials worked. Tested against the live servers from the prod host:
googleMailSender 535 5.7.8 Username and Password not accepted (BadCredentials)
-- the app password in the source is no longer valid
relay over IPv4 250 OK for MAIL FROM:<noreply@smartdukaan.com>
relay over IPv6 550 5.7.1 Invalid credentials for relay
So promoting google would have replaced one broken default with another. The
relay is what actually delivers today and it becomes 'mailSender'. It does not
authenticate -- Workspace authorises it by allowlisted source IP -- so sending
as noreply@ is legitimate there and AuthenticatedIdentityMailSender correctly
leaves it alone.
googleMailSender stays available by qualifier. Point the default back at it once
a valid app password is issued for sdtech@smartdukaan.com.
Also noted in the javadoc: the relay allowlist covers the IPv4 address only, so
anything that prefers IPv6 will be refused. |
|
| 37474 |
15 d 11 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
mail: delete the dead SendGrid bean from cron, make the authenticated identity primary
The @Primary bean named 'mailSender' was SendGrid, so every unqualified
JavaMailSender injection got it -- and SendGrid rejects with 535, which is what
was failing 10 report/notification cron jobs (dailyTrackingReport,
monthlyTargetForPartner, sendFeebackSalesAndRbm and others). 420 occurrences in
one log.
googleMailSender now answers to both 'googleMailSender' and 'mailSender' and is
@Primary, so those injections resolve to a sender that works and whose From is
rewritten to the authenticated identity. No call site changes. |
|
| 37472 |
15 d 12 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
IMEI activation: one snapshotted daily pass per brand, on one thread, with per-brand metrics
Four @Scheduled jobs every 5 minutes become two daily passes. Oppo and realme
share one thread and alternate in 25-imei chunks, so exactly one ChromeDriver is
alive at a time instead of four; vivo keeps its own thread since it is direct
HTTP and does not contend for a browser.
The pass snapshots its pool before any browser starts and walks that list to the
end. It never re-queries, and that is the actual fix. A failed lookup never
reaches dateMap.put, so no row is written, so createTimestamp is not bumped, so
the imei was eligible again on the next tick five minutes later. Measured 29-Aug:
realme issued 4,524 requests against 1,004 distinct imeis -- 4.5 asks each, 78%
of the day's budget spent re-asking -- while oppo, which rarely fails, sat at
1.03. More requests hardened the block, which caused more failures. A pass bounds
that: a failure costs one retry tomorrow, never one in five minutes.
This supersedes the r37447/r37448/r37449 argument about driver count, which was
about the wrong variable. That argument blamed realme's collapse on CPU
contention pushing the captcha render past the element waits. The logs do not
support it: on 29-Aug oppo took ZERO canvas timeouts across all 24 hours on the
same box, same six cores, same driver count, same captcha vendor, load average
0.9 -- including the 15:00-23:00 window in which realme solved nothing at all.
Realme's own canvas wait is 15s against oppo's 8s, so the longer wait is the one
expiring. What realme's timeout rate tracks is its own daily request volume, and
it resets at midnight: 920/day -> 0.3%, 3,467/day -> 28%, 4,524/day -> 75%. That
is realme.com declining to serve the widget.
DAYS=0 is deliberate and is not an off-by-one: the pool filter is
createTimestamp < now().atStartOfDay().minusDays(DAYS), so DAYS=1 measures
against yesterday midnight and silently yields a two-day cadence, which is what
oppo and realme were running.
Sizing measured on prod for a midnight start: oppo 4,133 and realme 2,118 imeis,
11.7h + 8.4h = 20.1 hours of a single thread. It fits with no slack; if the
'pass finished' counts come in short of 'pass starting', the lever is DAYS=1
rather than a second thread.
Observability: ImeiActivationGauges publishes the funnel per brand on
/actuator/prometheus, which alloy already scrapes on this host -- due, churned,
captcha_shown, captcha_solved, answered, dates_found, errors, run_seconds and
last_finish_epoch. Each stage fails differently and says what broke. Rates are
left to PromQL. The stage that matters for health is answered: churned>0 with
answered==0 is precisely the shape of both silent outages this year (oppo wrote
nothing for a week; the vivo captcha solver was dead for 46 days). dates_found is
deliberately NOT a health signal -- when the multi-year backlog drained at the
end of August, yield fell from ~100% to 2-3% on the same day across all three
brands with nothing broken.
Nagios cleanup: the Nagios server and every NRPE daemon are gone, so
WriteToPropertiesFile and the commented-out blocks that fed
nagios-cron.properties are deleted, and NagiosMonitorTasks is renamed
BalanceMonitorTasks for the transport it actually uses. Noted there that nothing
calls it -- there is no @Scheduled entry and no other caller -- which is why both
balance gauges have always read -1. |
|
| 37470 |
15 d 12 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Remove dead Itel/Tecno SAP activation services
Both services call SAP OData endpoints that Transsion decommissioned on 2024-11-20:
ItelImeiActivationService -> cms.itel-mobile.com:8099/.../ZTERTIARY_SALES_REPRT_SRV
TecnoImeiActivation -> cms.tecno-mobile.com:8099/.../ZTERTIARY_SALES_REPRT_SRV
Both hosts now refuse connections outright (verified from the prod app server).
That decommissioning is what stopped Itel and Tecno activation ingest within the
same hour on 2024-11-20; everything since has arrived via manual CSV upload.
Neither service has produced a row in 21 months and neither can again.
Removed:
- both service classes
- ScheduledTasks.checkItelImeiActivation / .checkTecnoImeiActivation, their
@Autowired fields and imports (the only callers)
- the --checkItelImeiActivation / --checkTecnoImeiActivation startup args
Unaffected: ItelImeiActivationNewService and checkItelImeiActivationNew, which
target the current imwav portal and were fixed in r37467. |
|
| 37453 |
17 d 21 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Build googleMailSender as AuthenticatedIdentityMailSender
The bean authenticates as sdtech@smartdukaan.com, so Google Workspace only permits
that address in From. Callers hardcode noreply@, which Gmail refuses with 535
'Authenticated user is not authorized to send mail', silently dropping every alert
sent through it. The sender now rewrites From to its own username at send time.
See profitmandi-common r37451. |
|
| 37416 |
20 d 14 h |
vikas |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Port two cron WhatsApp call sites left behind by r37409/r37415.
OrderTrackingService sends the ORDER_DELIVERED template with the airway bill
as its only variable; the push notification on the same loop keeps its
formatted sentence, since template wording lives in Meta, not the call site.
Application drops the userMobileNumberOptIn and authUserMobileNumberOptIn CLI
options, whose NotificationService.optIn backing went with the Gupshup gateway.
ScheduledTasks.java is deliberately not in this commit: locally it also carries
unrelated in-flight remark-scoring work whose package is still unversioned, so
committing it would put @Autowired RemarkScoreRunner into trunk with no such
class. Its two WhatsApp call sites (optIn at ~4618, sendWhatsappMessage at
~5276) therefore still fail to compile at HEAD and need a follow-up. |
|
| 37369 |
26 d 17 h |
amit |
/trunk/ |
Fixed mail sender everywhere |
|
| 37368 |
27 d 8 h |
amit |
/trunk/profitmandi-cron/src/main/ |
Cron: raise SMTP timeouts, rotate app password, add offer-circular ingest keys
- SMTP 10s -> 30s connect / 120s read-write on both senders; the 10s read timeout was
cutting off larger attachment sends. App password rotated to match the current
Google account credential.
- offer.circular.ingest.enabled / offer.circular.review.url added to dev, staging and
prod. Off by default in all three: enabling it makes the job pick up DRAFT circulars
uploaded from the FOFO portal, parse them and mail the uploader, which should only be
switched on once offer.circular.dir is a real path in that environment. There is no
fallback between profiles, so the key has to exist in each one. |
|
| 37340 |
28 d 13 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Fixed max limit to 15 lac for Credit limit |
|
| 37326 |
29 d 11 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/ |
Add --backfillMissingEwb cron arg
Runs InvoiceService.backfillMissingEwb over an explicit invoice list:
--backfillMissingEwb --invoiceNumbers=A,B,C [--dryRun]
Explicit list rather than a date window so the backfill only touches the invoices known
to have lost their EWB. NOT_SUPPORTED on the RunOnceTasks wrapper suspends the
class-level transaction, keeping the NIC lookups outside one. |
|