Subversion Repositories SmartDukaan

Rev

Show changed files | Directory listing | RSS feed

Filtering Options

Rev Age Author Path Log message Diff
37331 3 h 32 m amit /trunk/profitmandi-fofo/src/main/ Add offer circular review and curation screen

Shows the nine verbatim PDF columns beside what the parser made of them, uploads a
new monthly circular, and resolves the products the matcher could not.

Upload deliberately does not parse - it stores the PDF, sha256-deduped, and
registers it DRAFT, so an upload can never half-populate the offer tables. The cron
ingest job picks it up from there.

The curation queue groups by distinct (division, raw text) because that is the
product_alias key: one answer clears every row carrying that text, on this circular
and on every later one. On the Aug'26 circular that turns 152 unresolved rows into
106 decisions. Three actions mirror product_alias.action - PIN to a catalog id,
REWRITE to the catalog's spelling and match again, or IGNORE.

- Writes product_alias only, so nothing the screen does can set manually_curated
and lock a circular against re-ingest. Coverage decisions, which do need that,
are listed but visibly parked rather than offered a naming answer.
- A saved decision changes nothing until re-ingest, because aliases are read at
ingest time; the queue says so and the re-ingest button puts the document back
to DRAFT for the scheduler. The portal cannot run the ingest itself - that lives
in profitmandi-cron, which fofo does not depend on.
- The closest rejected match is shown for context and never pre-selected. Four new
OnePlus models each "nearly" matched a 2015 OnePlus 2 at 0.80-0.84, and offering
that as a suggestion invites a reviewer to confirm it. Where the catalog has no
such SKU the search says so and steers to IGNORE.
- aliasExport emits every decision as replayable SQL, because the portal writes to
one database and environments would otherwise drift apart silently.

Access is an email allowlist AND the admin role. Both are enforced in the
controller; the sidebar entry repeats the allowlist because visibility in auth.menu
is role-driven and cannot express a per-email rule.

No jsVersion bump: offer-circular-review.js is a new file that was never cached,
so it needs no cache-buster, and churning that shared counter only conflicts with
whoever is mid-edit on it.
 
37330 6 h 43 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 6 h 44 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 8 h 25 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 10 h 5 m ranu /trunk/ super retailer club 5 live  
37326 10 h 28 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 10 h 28 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 11 h 19 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 11 h 23 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 12 h 6 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 12 h 6 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 8 h ranu /trunk/profitmandi-dao/src/main/resources/ one assist ew at 99 up to 20k  
37319 3 d 9 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 11 h ranu /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/controller/checkout/ v2 version some fixes  
37317 3 d 11 h vikas /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/dtr/ Active Scratch Offers  
37316 3 d 12 h vikas /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/dtr/ Active Scratch Offers  
37315 3 d 12 h vikas /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/dtr/ Active Scratch Offers  
37314 3 d 14 h amit /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ Fixed max limit to 15 lac for Credit limit  
37313 3 d 15 h ranu /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ v2 version some fixes  
37312 3 d 15 h ranu /trunk/ one assist ew at 99 up to 20k  

Show All