Subversion Repositories SmartDukaan

Rev

Show changed files | Directory listing | RSS feed

Filtering Options

Rev Age Author Path Log message Diff
37632 50 m aman /trunk/ fix(loi): don't leave an LOI half signed when the signed PDF fails to save

Confirm Sign stores the partner OTP (/validateLoiOtp) before the browser builds and uploads the
signed PDF (/saveLoiDoc). When that second step failed - html2pdf not loaded from cdnjs, upload
rejected, tab closed, server error - nothing was shown, no LOI mail went out, no onboarding was
created, and because loiOtpPresent hid Generate LOI the filler could never re-sign (LOI 734).

- pendingFormList: loiOtpPresent only when OTP AND loiDoc are both saved; new loiSignIncomplete
flag shows a red "signed LOI not saved" note on the Pending LOI list (web + V2 app).
- loi-form.js Confirm Sign: every failure after the OTP says the LOI was NOT saved and how to
retry; checks html2pdf is loaded; success alert only after /saveLoiDoc confirms; no double submit.
- /saveLoiDoc (fofo + V2): refuses a document without a verified OTP; a repeat call for an
already saved LOI is a no-op (no second mail / completion).
- /validateLoiOtp (fofo + V2): clear message when no OTP was sent in 24h; reports the real
rejection reason (e.g. OTP already used) instead of always "wrong".
- sendSignedLoiPdfToPartner: filler without a manager no longer throws and rolls back the save.
- OtpProcessor.generateOtp: never hands back an already verified OTP under the 2-minute throttle.
- AppConfig version 423 for loi-form.js.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhJD2sc6pf3Zd7f4hyGxhH
 
37631 1 h 50 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.
 
37630 1 h 50 m amit /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/ feat(mail): wire inactive-recipient filter and clean hardcoded addresses

Wire MailRecipientFilter into googleMailSender and gmailRelaySender. Remove inactive/unknown addresses from recipient and access lists, bulk uploader gate to akhil.kumar.
 
37629 1 h 50 m amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/ feat(mail): wire inactive-recipient filter and clean hardcoded addresses

Wire MailRecipientFilter into googleMailSender and gmailRelaySender. Remove inactive/unknown addresses from recipient and access lists, fix typo addresses, bulk uploader gate to akhil.kumar, V2 brand fee gate to kamini.sharma.
 
37628 1 h 50 m amit /trunk/profitmandi-dao/src/ feat(mail): filter inactive auth users from outgoing mail

InactiveAuthUserRecipientFilter drops @smartdukaan.com recipients whose auth.auth_user is inactive (cached, 5 min refresh, fail-open). Remove inactive hardcoded recipients (sm@, praveen.sharma, tejus.lohani).
 
37627 1 h 50 m amit /trunk/profitmandi-common/src/ feat(mail): drop inactive recipients before send

Add MailRecipientFilter and RecipientFilteringMailSender, which strips To/Cc/Bcc addresses the filter reports inactive and skips a mail left with no recipients instead of failing. AuthenticatedIdentityMailSender now extends it.
 
37626 20 h 9 m amit /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/service/warehouse/ test(billing): assert internal transfer and billing resolve the same external origin vendor  
37625 20 h 9 m amit /trunk/profitmandi-dao/src/main/ fix(internal-movement): trace serial origin to the latest external purchase, matching billing

- resolveInternalMovementPrices orders the serial's external purchases newest first (was oldest), so transfers and billing name the same original vendor; no in-stock unit on prod changes (0 of 3,734)
- Restore resolveInternalMovementPrices javadoc onto its own method
- Add drop_internal_vendor_catalog_pricing_20260914.sql, as run on prod 2026-09-14 17:33 (15 New Spice internal suppliers; backups _bak_vcp/_bak_vcpl_internal_20260914)
 
37624 21 h 55 m amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ feat(price-drop): auto-approve V2 price drop DP/MOP into external vendor catalog pricing  
37623 21 h 55 m amit /trunk/profitmandi-fofo/src/ feat(price-drop): auto-approve price drop DP/MOP into external vendor catalog pricing

- PriceDropController calls VendorCatalogPricingService.applyPriceDrop with the affected date and logged-in user
- BillingPricingServiceTest: local-DB integration tests (rolled back) for origin-based billing prices, catalog fallback and re-billed orders
 
37622 21 h 56 m amit /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ feat(billing): price warehouse billing from the external supplier of the billed stock; auto-approve price drop DP/MOP into vendor catalog pricing

- BillingPricingService resolves TP/NLC per order from vendor_catalog_pricing of the most recent external supplier of the units scanned out (serial trace, else own external PO); units reversed by SALE_RET are ignored
- Falls back to the latest approved external catalog price when no supplier can be traced; vendorId stays the warehouse vendor
- addBillingDetailsForGrouppedOrders no longer reads vendoritempricing (removes NPE when the row is missing); order.vendorId set to the origin supplier
- VendorCatalogPricingService.applyPriceDrop writes approved pricing logs for external vendors with the price drop DP/MOP, keeping each vendor's TP on the effective date
 
37621 21 h 57 m amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ V2 /entity honours activeOnly, defaulting to false

Same defect as the fofo endpoint fixed in profitmandi-fofo r37620: the flag was
accepted and ignored. Defaulting to false keeps callers that omit it unchanged.
 
37620 21 h 57 m amit /trunk/profitmandi-fofo/src/main/ Offer creation suggests only active models unless asked for all

/entity accepted activeOnly but always searched with false, so the offer
screen's model picker listed every catalog of the brand, delisted ones included.
It now honours the flag. The default becomes false so the pages that never pass
it keep their current results; the notification product search, which already
asked for active-only, now gets it.

Each item-criteria block gets an Include inactive checkbox, off by default.
Ticking Exclude ticks it too: a brand-level offer still pays on delisted models
partners hold stock of, and they cannot be excluded if they cannot be picked.
Inactive models are labelled, and reloading the list keeps picks still present.

The reload flag is now per block; the old global one let a brand change in one
block be consumed by opening another, leaving the first with a stale list.
Brand names are URL-encoded so a brand like Ai+ is not sent as 'Ai '.

Requires profitmandi-common r37619 for the inactive label.
 
37619 21 h 57 m amit /trunk/profitmandi-common/src/main/java/com/spice/profitmandi/common/solr/ Return active_b in the unlimited content search

The offer screen's model picker needs to mark delisted models as inactive when
it is asked to include them. The other unlimited-search callers read only
catalogId_i and title_s, so the extra field changes nothing for them.
 
37618 23 h 54 m ranu /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ logger added  
37617 1 d 9 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.
 
37616 1 d 9 h amit /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/migrations/ Split a line item's serials into one inventory unit each

A serialised line item carries one serial per unit in serial_number, comma separated. The internal
GRN passed that whole field across as a single serial, so a line of four units became one unit whose
serial was the four serials joined together - a string no scan can ever match. Where the joined
string ran past the 128 characters the inventory column allows, the receipt failed outright; where it
fitted, it was accepted and the stock was quietly understated.

The serials are now split out and each unit is received on its own, which is what grnPoModels expects
- it creates one inventory row per serial.

A serial count that does not match the line's quantity now skips the invoice. Receiving fewer units
than were billed is exactly the failure this had, and it is not something to infer a best guess from:
the invoice is left for someone to look at instead.
 
37615 1 d 10 h amit /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/migrations/ Receive internal transfers the way the portal does, not via the Excel upload

The live run failed on every invoice with "Column 'status' cannot be null". The Excel upload path it
was calling, addPORowModels, persists a supplier invoice without ever setting a status, and the
column does not allow one to be absent, so that route cannot complete a receipt at all.

Rather than change a path the portal shares, this follows what the Receive Invoice screens actually
do: record the supplier invoice, record its items through InvoiceService.createInvoiceItem, then hand
it to PurchaseOrderService.grnPoModels, the call behind the Create GRN button. grnPoModels sets the
invoice to received itself, so the status is never left for the caller to remember.

Recording the invoice items matters beyond the receipt: warehouse.invoice_item is what the buying
reports join against, and the Excel path never wrote those rows either.

An invoice is carried as one entry per item rather than one per order, since that is the shape
grnPoModels expects - every serial of an item arrives together and a non serialised item arrives as a
single quantity. There is no supplier document to attach, which is ordinary here; most existing
warehouse invoices carry none.

Resolving the purchase order now uses the mapping recorded when the internal PO was raised - the
transaction it created, held on the purchase order - instead of walking every order to find it.
An invoice whose orders do not share that one transaction is skipped rather than guessed at.
 
37614 1 d 10 h amit /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/migrations/ Run each internal GRN in a transaction that is actually applied

The internal GRN one-off failed immediately with "no transaction is in progress", thrown while
flushing the Hibernate session at commit.

The per invoice method was annotated to start its own transaction, but it sat in the same bean as
the loop that called it. Spring applies @Transactional through a proxy, and a call from one method
of a bean to another never leaves the object, so the annotation was inert - the receiving ran with
no transaction at all while the driver had suspended the surrounding one. The repositories still
bound a session to the thread, and the flush at commit then found nothing to flush into.

The receiving moves to its own bean, so the driver now reaches it through the proxy and the
transaction is real. The driver keeps no transaction of its own, which is what lets one invoice
fail without disturbing those already received.

No change to what is received or to the conditions under which an invoice is skipped.
 
37613 1 d 11 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.
 

Show All