| Rev |
Age |
Author |
Path |
Log message |
Diff |
| 37330 |
51 m |
amit |
/trunk/profitmandi-cron/ |
Add Pine Labs affordability circular parsing and ingest
Turns the monthly OEM "Mobile & Laptop Offers" PDF into the offers schema: tabula
extraction to nine verbatim columns per row, per-cell parsers for benefit, tenure,
bank and footnote text, catalog matching, and a scheduler that claims DRAFT
documents uploaded from the FOFO portal and emails the uploader the outcome.
Ships inert. offer.circular.ingest.enabled defaults to false, so the scheduler does
nothing until an environment opts in, and offer.circular.review.url defaults to
empty - neither key is required for the context to start.
- tabula added here and not in profitmandi-common so PDFBox never reaches the
web/fofo WARs; bouncycastle, slf4j-simple and jai-imageio excluded (version
clash, duplicate SLF4J binding, and unused image decoding respectively)
- offer_raw_row holds all nine columns verbatim, so re-parsing reads the table and
never the PDF again
- product_alias is consulted before matching, so a human confirmation recorded once
keeps applying every following month
ProductNamesTest locks in the product-name parsing, which decides which SKU an
offer's money lands on. Every case there is a real mis-parse, and they share one
root cause: characters or digits belonging to the model name being eaten as memory
or stripped as punctuation. Two worth naming:
- A memory spec with no GB/TB unit is still a memory spec. Motorola writes
"(8+256)" and vivo "(8+256G)"; unrecognised, the matcher believed no size was
given and bound the offer to an arbitrary sibling - a 1,000 Edge 60 Pro 8+256
offer and a 2,000 12+256 offer landed on the same SKU.
- Two variant groups written back-to-back are two products. "Edge 70 Pro
(8+256)(12+256)" stayed one product bound to a single SKU while the 12+256
variant silently got no offer at all.
Bundled accessories are deliberately NOT stripped back to the bare phone. Doing so
resolves 30 CATALOG_GAP rows and looks safe on Oppo, whose bundled and bare rows
carry identical values - but vivo caps X300 Pro(16+512G) at 10,000 on its own row
and 11,000 on the "+Extender" row, the difference being the Extender. Merging them
would let the bundle's cap be claimed on a phone sold without the accessory.
Whether a bundle offer transfers to the bare SKU is a commercial question the PDF
does not answer, so it is a manual coverage decision, not a parsing rule.
Verified against the Aug'26 circular on the local DB: 324 rows in the PDF, 239
loaded, producing 361 benefits, 511 tenures, 911 bank links and 663 products, of
which 74% resolve automatically. ProductNamesTest 11/11. |
|
| 37329 |
52 m |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/ |
Add offers-schema repositories for the Pine Labs affordability circular
Three repositories over the offers schema, split by who is allowed to write what:
- OfferCircularRepository - read side for the review screen (verbatim rows,
documents, per-offer parsed detail)
- CircularIngestRepository - write side for ingest; claims a DRAFT document with
a guarded UPDATE and deletes only rows derived from that one document, so
re-ingesting one month cannot disturb another
- OfferCurationRepository - write side for manual curation
The split is deliberate: a caller that only displays circulars should not hold a
handle that can rewrite the scope config or the offer tables.
OfferCurationRepository writes offers.product_alias and nothing else. An alias is
config, keyed on (division_id, raw_text), so re-ingest reproduces it and one
decision carries into every later circular. Writing offer_product instead would be
derived data that re-ingest deletes, which is why doing so has to set
manually_curated and freeze the circular permanently - not a trade worth making for
a naming decision, so this repository cannot make it.
A PIN is validated against the division's own brand and category before it is
stored. Nothing downstream re-checks a pinned id - the matcher takes it at face
value - so an unverified exception would silently mismap money. |
|
| 37328 |
2 h 33 m |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/integrations/gstpro/ |
Fetch a fresh EWB auth token when the cached one is stale
Two defects made an expired EWB token unrecoverable, surfacing as GSP102
"eInvoice AuthToken not found or expired" on every GET.
1. ewbApiGet's retry was unreachable. NIC returns GSP102 with HTTP 400, and
RestClient.execute throws GE_1005 on any non-2xx before returning the body, so the
'if (response.contains("GSP102"))' branch could never run. A failed first attempt is
now treated as a possibly-stale token and retried once with a freshly minted one; a
second failure propagates. The POST path was unaffected — executeJson does not check
status, so its retry already worked.
2. Eviction targeted the wrong cache. The token is cached in redisCacheManager but all
three sites evicted through redisFortnightlyCacheManage, a different cache, so the
eviction was a silent no-op and the stale token survived. Eviction now goes through
GstProAuthService.evictEwbAuthToken, declared beside the @Cacheable and pinned to the
same cacheManager so the two cannot drift apart again.
Found while dry-running the EWB backfill, which failed on the first invoice. |
|
| 37327 |
4 h 12 m |
ranu |
/trunk/ |
super retailer club 5 live |
|
| 37326 |
4 h 35 m |
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. |
|
| 37325 |
4 h 35 m |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/invoicing/ |
Add EWB backfill for invoices whose IRN was recovered via DUPIRN
When GenerateIRN carries EwbDtls, NIC files the IRN and e-way bill together and reports
the EWB back only in that response, flagged by InfoDtls[InfCd=EWBPPD]. A read timeout
sends the retry down the DUPIRN path, which recovers the IRN via the get-e-invoice
endpoint — that response carries neither InfoDtls nor EWB fields. The EWB therefore
exists at NIC while ewb_no stays null locally, and since updatePdfModelWithIrnDetails
gates the entire e-way bill section on ewb_no, the stored PDF omits it altogether.
backfillMissingEwb() looks the EWB up by (seller GSTIN, ack date), matches on docNo, and
takes actualDist from the per-EWB call since the distance is printed on the invoice. It
then re-renders the PDF; generateIrnForInvoices returns early once irn_generated is set,
so nothing is re-filed at NIC.
NIC is queried with the transaction suspended (NOT_SUPPORTED); the write and the
re-render each run in their own REQUIRES_NEW transaction. |
|
| 37324 |
5 h 26 m |
aman |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
Lead Management: restrict lead view to field-level sales only (L1-L3). Any SALES position at any level previously forced the own+reportees lead filter, so senior sales heads (L4+ BM/RSM/NSM/co-founder L7) lost visibility of all leads and their dashboard charts collapsed. hasCategory check replaced with isFieldSales() at both view-filter sites; assignee validation untouched. |
|
| 37323 |
5 h 30 m |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ |
Drop irn_attempt_count; IRN transport retry is unbounded
Removes the attempt counter added in r37322 along with its pending ALTER TABLE, so the
change no longer carries a schema dependency.
NIC outages resolve within the day, and an invoice legally requires an IRN, so capping
the retry would not remove the obligation — it would only stop trying. Transport failures
now stay queued (irn_generated NULL) until the provider recovers; only a genuine rejection
from NIC is terminal. The failure reason is still recorded in irn_error_message, which
distinguishes a requeued transport failure from an invoice never yet attempted. |
|
| 37322 |
6 h 13 m |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ |
Stop treating IRN transport timeouts as terminal; isolate NIC calls from batch transaction
A read timeout to GSTPro/NIC was recorded as a final verdict (irn_generated=false),
so 79 invoices billed on 2026-08-17 were left permanently without an IRN even though
NIC may well have filed them. A timeout means the call never completed, not that the
document was rejected.
- markEInvoiceFailed -> recordIrnFailure(invoiceNumber, Throwable): transport failures
leave irn_generated NULL so the cron retries (DUPIRN recovers anything NIC did file);
only a genuine rejection is terminal. Alert email now fires only when terminal.
- New einvoice_details.irn_attempt_count bounds that retry at 10 attempts, reset on
success, so a prolonged NIC outage still converges instead of looping forever.
Requires the matching ALTER TABLE before deploy.
- New saveInvoiceInNewTransaction(invoiceNumber): REQUIRES_NEW per invoice, reloading
orders inside it. RunOnceTasks has class-level @Transactional wrapping the whole
batch loop, so every NIC call previously ran inside one transaction holding write
locks on all orders in the batch; at 60s per call that window is unacceptable.
updateIrnsToInvoices and regenerateBilledInvoices now carry only invoice numbers,
keeping the batch transaction read-only.
- Route all NIC calls (IRN gen, auth, cancel, EWB) through the 60s regulator profile
via GstProAuthService.nicRestClient(). getGstDetails stays on the 10s default since
it runs on request threads. |
|
| 37321 |
6 h 13 m |
amit |
/trunk/profitmandi-common/src/main/java/com/spice/profitmandi/common/web/client/ |
Preserve transport-failure cause in RestClient; add 60s regulator timeout profile
RestClient wrapped IOException/ClientProtocolException into RuntimeException(GE_1006)
without a cause, so callers could not tell a read timeout apart from a business
rejection. Pass the original exception as the cause at all four transport catch sites;
message text is unchanged.
Add HttpClientFactory.slowRegulatorRequestConfig() (60s socket) for NIC e-invoice/EWB
calls, which routinely exceed the global 10s default at peak, plus a RestClient
constructor taking an explicit RequestConfig. The global default is unchanged. |
|
| 37320 |
3 d 3 h |
ranu |
/trunk/profitmandi-dao/src/main/resources/ |
one assist ew at 99 up to 20k |
|
| 37319 |
3 d 3 h |
amit |
/trunk/ |
Fix partner-performance tertiary: aggregate order items (qty*mop), not the POS-typed order header
The tertiary panel summed fofo_order.total_amount - a price typed at the partner POS
and never validated against the catalogue - and attributed each whole order to its
first line item's brand via .get(0). One mistyped digit inflated reported sell-out
10x, and mixed-brand orders booked 100% to the first brand, leaving the rest at zero.
Defect dates from r32000/r32034 (May 2023); the panel was the only tertiary consumer
diverging from the qty*mop basis.
- New FofoOrder.selectMonthlyBrandTertiary: sum(quantity*mop) grouped by
(year*100+month) and item brand - the same basis selectPartnerTertiarySales
already uses for the DSR and the partner tier calculation
- PerformanceController: replaces two entity-loading queries (every FofoOrder and
FofoOrderItem for 6 months) with one aggregate; all items now count, each under
its own brand
- Month labels unchanged - toMonthLabel rebuilds the MMM''uu key, template untouched
- Remove V2FofoPerformanceController, the /v2/fofo JSON copy carrying the same defect
Verified against dev DB for fofo_id 175139501: Jul 2026 now 16,94,939 (panel
previously showed 50,92,440); all six months match the qty*mop basis. |
|
| 37318 |
3 d 5 h |
ranu |
/trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/controller/checkout/ |
v2 version some fixes |
|
| 37317 |
3 d 6 h |
vikas |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/dtr/ |
Active Scratch Offers |
|
| 37316 |
3 d 6 h |
vikas |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/dtr/ |
Active Scratch Offers |
|
| 37315 |
3 d 6 h |
vikas |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/dtr/ |
Active Scratch Offers |
|
| 37314 |
3 d 8 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ |
Fixed max limit to 15 lac for Credit limit |
|
| 37313 |
3 d 9 h |
ranu |
/trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ |
v2 version some fixes |
|
| 37312 |
3 d 9 h |
ranu |
/trunk/ |
one assist ew at 99 up to 20k |
|
| 37311 |
3 d 21 h |
vikas |
/trunk/ |
Scratch Offers code modify |
|