| Rev |
Age |
Author |
Path |
Log message |
Diff |
| 37850 |
3 d 5 h |
amit |
/trunk/profitmandi-dao/src/main/ |
refactor(warehouse): retire hardcoded Delhi ids - allocation fallback vendor warehouse 7573 -> 13368 (central HR-NSSPL/GGN); Vivo Noida/Ghaziabad partner-sale rule 7573 -> 13370; drop unused InventoryWarehouse WH_DL/WH_HR_DL/WAREHOUSE_IDS; migration 20261005_hr_ggn_central_brand_mapping.sql (13368 central for every ACTIVE warehouse, all brands except Oppo/Vivo, 532 rows, applied on hadb1) |
|
| 37845 |
3 d 6 h |
amit |
/trunk/profitmandi-dao/src/ |
feat(warehouse): ACTIVE/SUSPENDED/INACTIVE status + label on sellerwarehouse replace WAREHOUSE_MAP - BillingWarehouseService (active for dashboards, active+suspended for warehouse screens, names in every state, 5 min cache); setup service: guarded status change (no suspend while franchise stores or brand mapping route there, no close while stock/unshipped orders), rename, all-warehouse overview with usage; partner store assignable only to an active warehouse; daily stock alert for suspended/inactive warehouses to logistics/accounts top 2 staffed levels + leadership; dashboard warehouse list = active (replaces r37834 stock-holding loop); migration sellerwarehouse_status_display_name_20261005.sql (applied on hadb1) |
|
| 37830 |
6 d 23 h |
amit |
/trunk/profitmandi-dao/src/ |
feat(movement): one PO per source vendor warehouse and cost - layers carry their GOOD/OURS vendor warehouse, orders are raised pinned to it, holds of pinned orders come off their own warehouse, billing takes units at the order's price first |
|
| 37829 |
7 d 0 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ |
fix(order): split order's line item carries its item, so the split can be billed or split again in the same transaction (NPE at addBillingDetailsForGrouppedOrders) |
|
| 37816 |
8 d 9 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/ |
fix(einvoice): save the e-way bill whenever NIC returns EwbNo, not only with the EWBPPD note
GstProService saved EWB details only when InfoDtls held EWBPPD. NIC sends that
note (its pin-to-pin distance) only when we pass Distance=0, and the DUPIRN
get-by-IRN response carries no InfoDtls at all. So every partner with a
warehouse_partner_distance_mapping row, and every IRN recovered after a
timeout, lost its EWB although NIC had filed it (13 + 2 invoices in 30 days,
backfilled 2026-09-30), and a false "EWB Not Generated" mail was sent.
- Key on EwbNo; distance from EWBPPD, else the distance we sent, else none.
- Invoice PDF prints the "[distance]" suffix only when a distance is known
(was "[null]"). |
|
| 37792 |
10 d 9 h |
amit |
/trunk/profitmandi-dao/src/ |
feat(cart): carry bag at Rs 1 per smartphone over Rs 12,000, extras at listing price
One carry bag (item 32046) is priced at Rs 1 for each smartphone (category
10006) in the cart selling above Rs 12,000; bags beyond that count are priced
at the carry bag's listing price, and Bronze partners pay listing for all.
Closes the leak where bag-only carts of hundreds of bags at Rs 1 were placed
from the old app. CarryBagQuote (via CartService.getCarryBagQuote) is the
single rule; the cart carries it as one line at a blended price.
- CartService/CartServiceImpl, CartResponse, OpenCartValidationResult: expose
the quote on the cart.
- OrderLineAllocator: an item may now have more than one cart line (the flat
and listing-priced parts); its units fill the lines in order.
- TransactionServiceImpl: item quantities merge instead of failing on a
duplicate item id.
- PurchaseServiceImpl: partner GRN creates one stock record per billed price;
the GRN screen shows the blended unit price; dead
createScannedNonSerializedItem removed.
- PurchaseReturnServiceImpl: debit-note PDF picks the order billed at the
returned stock's price; refundOrder spreads a non-serialized return over the
item's orders with room left (same price first) instead of loading it all
on the first order.
Tests: CarryBagQuoteTest 6/6, OrderLineAllocatorTest 13/13.
Deploy with profitmandi-web (same change) and the partner apps. |
|
| 37776 |
14 d 4 h |
amit |
/trunk/profitmandi-dao/src/main/ |
returns: reverse a refunded debit-note return whose goods never reached the warehouse
Once a return was refunded nothing could undo it - rejectReturn refuses an already
refunded one - so a return booked and paid for goods that never arrived left phantom
warehouse stock, the unit missing from partner stock, the order marked returned, a
wallet credit and a filed credit note, with no way back.
ReturnReversalService.reverse(imei, reason, by, dryRun) undoes exactly one unit:
the warehouse return scan (row deleted so a genuine return later is not rejected as a
duplicate) and the stock it added, partner stock with its schemes/price drop/offers,
the order's return quantity and status, the wallet refund as a REVERSAL entry, and the
return item / debit note. Guards refuse anything that has moved since the refund, and a
dry run reports the plan without writing.
The credit note follows movement and the NIC clock: inside the 24h window, and only
when the note credits nothing but this unit, its IRN is cancelled and the note marked
cancelled; past it a DBN with its own IRN is issued against the note
(CreditNoteService.issueReturnReversalDebitNote, stored as CN_CANCELLATION with no
margin month so the statement does not show it twice - the wallet REVERSAL is the
statement line); a note never filed at NIC is voided locally. Every local write happens
first and NIC last, so a refusal rolls the whole reversal back.
fofo.return_reversal (return_reversal_20260921.sql) records each reversal and, unique
per return item, makes it once-only. Also adds cancelled=0 to the RETURNS_CN branches of
the account statement queries, without which a cancelled note keeps crediting the
statement - no current effect, no RETURNS note is cancelled today. |
|
| 37767 |
14 d 6 h |
amit |
/trunk/profitmandi-dao/src/ |
fix(orders): movements ship from their source only; a row reserved beyond its stock gives nothing
Internal movement orders were allocated by the partner allocator, which spills a source
shortfall to every warehouse the brand mapping links to the destination - stock billed
there has no PO to be received against (PO 54279: 3 units put on Jaipur for a UP->Delhi
movement). createTransactionInternally now keeps the source's own rows only; a shortfall
still parks on the source's Dummy.
getItemQty took min(qty, netAvailability) on a row reserved beyond its stock - always the
case on a Dummy holding an open order - so a -1 row added a unit to the shortfall, which
then parked on the Dummy as an extra order (24 Sep: 9 units raised for a movement of 8,
refused by the cart-value guard). Rows with nothing free are now skipped and no longer
offset another row's free stock in the warehouse total.
Removes the empty, uncalled markOrdersAsGrnCompleted. |
|
| 37740 |
17 d 11 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ |
SD credit: getAvailableAmount no longer writes utilized_limit - it is a read path, but the managed entity was dirty-checked so every availability query (gateway callback, both sanction screens, bulk order creation) flushed an UPDATE; availability is now computed locally as limit - liveUtilization, same value |
|
| 37721 |
20 d 8 h |
amit |
/trunk/profitmandi-dao/src/ |
fix(orders): price each order by the cart line that asked for it, not the first line of its model
Orders were priced from one cart line per catalog, so colours of one model at different
prices all took an arbitrary one. Internal movements (cost layers) failed with WLT_1000
when the dearer line won and were silently under-billed when the cheaper one did.
fulfillQty now prices from the item's own line, newColorQty from the model's any-colour
line; same-price output is unchanged. Refuse the transaction if orders do not total the cart. |
|
| 37656 |
22 d 7 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ |
Point dao at the relocated KYC and SD Credit types (r37655)
Imports follow services.mandii -> services.kyc / services.sdcredit, and
RecordingService takes RawHttpResponse in place of MandiiResponse.
Gateway.MANDII is kept, with a comment saying why: it is persisted as a
string on FofoPayment.gateway and CreditAccount.gateway, and 740 historical
fofo.payment rows still carry it - removing the constant would make
Hibernate throw when reading them. |
|
| 37652 |
22 d 9 h |
amit |
/trunk/profitmandi-dao/src/main/ |
Internal store buyer address: always read user.address
An INTERNAL store is the buying identity of a warehouse, so order creation
resolved its address from transaction.warehouseaddressmaster while every
screen read transaction.addId -> user.address. The Delhi warehouses moved to
warehouseaddressmaster 26 in Sept 2024 and nothing carried that across, so
user.address still held the 2021 L-222 premises: same buyer, two addresses.
user.address for active internal stores is now aligned with the mapped
warehouse address (sql/20260916_sync_internal_store_addresses.sql), split
exactly as getCustomAddress() does so the next invoice is unchanged. With
that true, createTransactionForWarehouse no longer special-cases internal.
SellerService.syncInternalStoreAddresses carries a warehouse address remap
through to its internal stores - the mapping has no edit screen and is
repointed directly in the database, which is why nothing propagated before. |
|
| 37628 |
23 d 11 h |
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). |
|
| 37622 |
24 d 7 h |
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 |
|
| 37618 |
24 d 9 h |
ranu |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ |
logger added |
|
| 37504 |
37 d 8 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/invoicing/ |
Stop invoice read paths creating directories (AccessDeniedException 500s)
getInvoicePath called Files.createDirectories, and getInvoiceFile called it on every
download. Invoices are generated by the cron app as root, so /SaholicInvoices/<month>
is 755 root-owned; a download served by Tomcat cannot create a retailer subdirectory
and threw AccessDeniedException.
It threw on line 1 of getInvoiceFile, before the Files.exists check, so the
ProfitMandiBusinessException on the next line was unreachable and the callers'
deliberate 404 handler ("Invoice not yet generated, please retry shortly") never ran.
Downloads for a not-yet-generated invoice 500ed instead of 404ing - the exact log
noise that handler was added to remove.
Split the path computation out: resolveInvoicePath is side-effect free and used by
getInvoiceFile; getInvoicePath keeps the mkdir for the two generation callers
(InvoiceService:558, GstProService:952). The legacy relocation branch creates the
target directory only when there is actually a file to move.
No ops change needed - generation as root already works. |
|
| 37456 |
40 d 17 h |
amit |
/trunk/ |
Block billing when NIC rejects the transporter GSTIN for e-way bills
NIC files the e-way bill alongside the IRN, so a deregistered transporter
GSTIN returns Status=1 with InfoDtls[InfCd=EWBERR] (3029 "GSTIN - ... is
not active"): the IRN is valid while ewb_no stays null. Nothing downstream
reads that as a failure, so invoices kept being issued for goods that
could not legally move.
Cache the rejected transporter GSTIN in Redis and refuse to bill through
it. The block is keyed on the GSTIN, since one GSTIN is shared by several
warehouse_provider rows, and it carries the day it was raised so it lapses
at midnight and each new day re-tests NIC once. Correcting the GSTIN in
the provider panel lifts it immediately.
Only errors that are the transporter's fault block billing - NIC's 3029,
or any message naming the GSTIN we sent as TransId. Every other EWBERR
behaves as before: the IRN is filed and the e-way bill is retried later.
Guard sits in addBillingDetailsForGrouppedOrders before the pessimistic
lock and before any mutation, mirroring LogisticsServiceImpl#getEwbDetails
(order's own warehouse; self-pickup and runner skipped, as they travel on
a vehicle number rather than a transporter id). |
|
| 37421 |
43 d 8 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/ |
EWB: recover existing e-way bill on NIC 604 instead of storing a placeholder
DCNSUPDL948 generated EWB 451765074092 at NIC, then the transaction rolled back and
the number was lost. Every retry hit 604 and stored the literal EXISTING-LOOKUP-NEEDED
with no validity date, which routed the PDF down the transporter branch and NPE'd on a
self-pickup dispatch with no warehouse_provider row. ~640 retries in 55 minutes, and
because the failure surfaced as an Error it escaped catch(Exception) and blocked six
other documents behind it.
- GstProService: on 604, look the bill up via GetEwayBillsByDate + docNo match and
return it in GENEWAYBILL shape; stamp NIC's generation time instead of now().
Throw when it cannot be recovered rather than persist a placeholder.
- InvoiceService: saveInvoiceInNewTransaction no longer propagates. It commits
irn_generated=0 with the reason so a failed document stops churning; already-filed
invoices being re-rendered are left untouched.
- InvoiceService: cron loop catches Throwable so one bad document cannot skip the batch.
- InvoiceService: null-guard warehouse_provider; omit the transporter line instead of
failing the PDF.
- recordIrnFailure: transport failures now park at 0 for escalation rather than
requeueing for unbounded retry. |
|
| 37356 |
50 d 7 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ |
Fixed max limit to 15 lac for Credit limit |
|
| 37350 |
50 d 15 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ |
Fix SD Credit daily statement showing zero interest on overdue loans
sdDirectService classified each day's interest by exact-matching the
loan_statement description ('Interest On Loan Per Day' /
'Penalty On Loan Per Day'). Once a loan crossed its due date the cron
switches the label to 'Overdue Interest On Loan Per Day', which matched
neither filter, so the daily statement reported 0.00 interest for every
overdue day even though the charge was booked correctly in
loan_statement and loan.interest_accured.
Classify by tenure window against loan.getPenaltyDate() instead - the
same test addInterest() uses to pick the rate - and net the day's full
interest out of the opening balance so penalty days are consistent too.
Seen on loan 120277 (invoice NSLCK35860): Rs.73-83/day accruing from
08-Aug, displayed as 0.00. |
|