| Rev |
Age |
Author |
Path |
Log message |
Diff |
| 37631 |
20 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 |
20 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 |
20 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 |
20 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 |
20 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 |
18 h 39 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 |
18 h 39 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 |
20 h 25 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 |
20 h 25 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 |
20 h 26 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 |
20 h 27 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 |
20 h 27 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 |
20 h 27 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 |
22 h 24 m |
ranu |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ |
logger added |
|
| 37617 |
1 d 7 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 8 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 8 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 8 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 10 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. |
|
| 37612 |
2 d 10 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/ |
Value an internal PO's cart the same way the transaction validates it
Creating an internal PO failed with "Cart Value-Payment value mismatch" whenever a line
carried paise and the quantity was more than a handful. Two places were computing the same
cart total from the same stored float through two different decimal conversions, so they
disagreed on the value of prices binary cannot hold exactly.
createOrderInternally read WarehouseLineItem.unitPrice through String.valueOf, which
resolves a float via Float.toString and yields 10499.99, while createTransactionForWarehouse
re-values the persisted cart lines with BigDecimal.valueOf, which widens that same float to
double and yields 10499.990234375. The per-unit gap is around two ten-thousandths of a rupee;
quantity multiplies it, and it crosses the 0.001 tolerance the validator allows at a quantity
of five. Round prices are exact in binary and passed, which is why this looked intermittent
rather than total - across randomised carts the old arithmetic disagreed 98% of the time.
The total is no longer computed in its own loop. It is derived from the cart items that are
about to be written, using the conversion and the line-inclusion rule the validator applies,
so both sides are the same function over the same rows and cannot drift apart. That also
brings across two rules the PO side never had: quantities of zero or less, which
addItemsToCart drops and which therefore never reach the validated total, and the one paisa
carry bag, which the validator treats as a marker line rather than a billed one. Either of
those reaching an internal PO would have failed it outright, and a carry bag is only a
rounding error away from the paisa-per-unit pricing used for FOC stock.
The wallet top-up still truncates the total to whole rupees, and now lands within a rupee of
where it did before, well inside the twenty rupee buffer it already carried. Nothing outside
internal PO creation is touched: the validator, bulk orders and the refurb split keep their
existing numbers, and the wallet debit is driven by the order totals, not by this value. |
|