| Rev |
Age |
Author |
Path |
Log message |
Diff |
| 36507 |
4 d 4 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Skip Credit Note IRN generation for Delivery Challan (DC) returns — same GSTIN on both sides causes NIC rejection. Cancel EWB best-effort instead. |
|
| 36477 |
8 d 6 h |
amit |
/trunk/ |
Invoice return: IRN/EWB cancellation on approve, Logistics L2+ permission, DL GST disabled
- approveInvoiceReturn now cancels IRN+EWB when cancellable (path B) before falling back to Credit Note (path A)
- DC/challan EWB cancelled best-effort before Credit Note path
- Added enabled flag to GstEInvoiceUser; DL GSTIN disabled in E_INVOICE_USERS and EWB_USERS
- isGstEnabled guard added to all public GST API methods in GstProService
- Logistics L2+ can now approve/reject invoice returns (not just Finance)
- invoice-return.vm uses canApproveInvoiceReturn for INV-prefix button visibility |
|
| 36455 |
9 d 14 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Fix: populate saleQtyByKey for serialized items too, include DOA_IN in returnQtyByKey |
|
| 36450 |
11 d 8 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/ |
Refactor applyReceipt: extract scan creation to WarehouseInventoryService.recordReturnScan with validation for all return types (SALE_RET/DOA_IN/SALE_RET_UNUSABLE), qty>0, sold-qty capacity check, and SALE_RET warehouse capacity check |
|
| 36449 |
11 d 9 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Fix duplicate PurchaseReturnItem creation for serialized items - use list query with CREATED/APPROVED status check instead of single-result query |
|
| 36446 |
12 d 2 h |
amit |
/trunk/profitmandi-dao/src/main/ |
DN lifecycle: decouple rejection from restore, add DebitNoteStatus, retailer acknowledgment flow
- Add DebitNoteStatus enum (CREATED/RECEIVED/APPROVED/REJECTED/CANCELLED) on debit_note table
- Add retailer_acknowledge_timestamp on purchase_return_order
- rejectReturn() no longer calls restoreReturnedItems() — inventory stays reduced until retailer confirms goods received back
- New acknowledgeRejectedReturn(): retailer confirms receipt, restores inventory+schemes+offers, DN→CANCELLED
- Set DN status in receiveDebitNoteItems (RECEIVED), refundOrder (APPROVED), rejectReturn (REJECTED)
- notifyReturnRejected: updated message, added Finance L1+L2 to CC
- notifyItemsReceived: added Finance L1
- New notifyRejectedGoodsAcknowledged notification
- SQL migration with backfill for existing data |
|
| 36429 |
14 d 7 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/ |
Fix credit limit settlement not happening on billing and post-billing cancellation
createLoanForBilling has REQUIRES_NEW (added for lock isolation against
order row locks held by the billing method). Inside that new transaction it
queried orders to find which were just billed — but the billing timestamps
set in the suspended outer transaction are invisible, so the condition
always evaluates FALSE when all orders are billed in one call. The limit
block is never converted to a loan and never released.
Fix: remove the order query. The caller already passes invoiceAmount (sum
of walletAmount for the billed orders). Use it directly with Math.min to
cap at pendingAmount. REQUIRES_NEW kept for lock isolation.
Also: cancelInvoiceFully and applyInvoiceReturnViaCreditNote (post-billing
invoice cancellation/return paths) credit the partner wallet but never
settle the non-limit loan created during billing. Added settleLoan call
after wallet credit in both paths, guarded by settledOn == null check.
Data defect: 95 stuck limit blocks totaling Rs 56.95 lakh across partners.
Most have no actual loan created. Needs one-time remediation via
fixBlockedCredit() in ScheduledTasks. |
|
| 36427 |
14 d 11 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
rejectReturn: simplify to cancel-the-request semantics
After the receive/refund refactor, applyReceipt — and therefore every
warehouse-side effect (SALE_RET scans, WarehouseInventoryItem.addQuantity,
InventoryItem.returnTimestamp, ReturnOrderInfo, Order.status flip,
lineItem.returnQty) — only runs from refundOrder (or its inline
auto-approve sibling in submitReceiptForApproval). Both paths set
pro.refundTimestamp in the same transaction, all-or-nothing under
@Transactional(rollbackFor=Exception.class).
The refund_timestamp guard at the top of rejectReturn blocks rejection
once any of that has fired, which means rejectReturn is now ONLY
callable on a pending PRO — a state where applyReceipt has never run
and there is nothing on the warehouse side to undo.
The pre-existing reversal pipeline (warehouse-scan -1 reversal scans,
ReturnOrderInfo update/create-with-REJECTED, Order.status flip back to
DELIVERY_SUCCESS, lineItem.returnQty decrement) was therefore operating
against state that doesn't exist:
- lastScanType is SALE (from original sale), not SALE_RET, so
addQuantity(-1) gate correctly skipped — but the unconditional
persist of WarehouseScan(qty=-1, type=SALE_RET) was creating
fake reversal rows for receipts that never happened.
- selectByOrderId for ReturnOrderInfo always returned empty
(refundOrder is the only writer), and the no-rows branch was
fabricating REJECTED ROI rows for returns that were never received.
- Order.status was never flipped to COMPLETE_RETURN, so the
DELIVERY_SUCCESS reversal block correctly skipped — pure dead
branch.
Strip all of it. rejectReturn is now: guards (refund/reject timestamps),
stamp PRO with reject_timestamp/remark/updatedBy, restoreReturnedItems
to undo the partner-side effects from generateDebitNote(), mark items
REJECTED so a fresh re-request is possible.
This also undoes the previous fix #5 (extending the warehouse-scan
reversal to non-serialized) — that fix was making things worse by
creating fake reversal rows for both serialized and non-serialized
items instead of just serialized. The right answer was to delete the
whole block, not extend it. |
|
| 36425 |
14 d 12 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Sale-return reversal: idempotency guards + CN failure rolls back + non-serialized reject reversal
rejectReturn (#1): add refundTimestamp / rejectTimestamp guards. Without
them a stale-tab click or retry could re-run the full reversal pipeline
on an already-refunded DN — reversing scans twice, re-running
restoreReturnedItems (re-credits scheme amounts to wallet on top of the
refund that already paid out), and stamping rejectTimestamp on top of
refundTimestamp. Mirrors refundOrder's existing guard pair.
refundOrder CN block (#2): replace the swallow-and-log with a re-throw
on IRN failure. With class-level @Transactional(rollbackFor=Exception),
the prior catch caused commits of an advanced sellerWarehouse sequence
+ orphan CreditNote / CreditNoteLine rows whenever the NIC IRN call
failed. Restructured as straight-through; IRN failure now rolls the
whole refundOrder transaction back so finance retries cleanly. Matches
the symmetric path in applyInvoiceReturnViaCreditNote.
applyInvoiceReturnViaCreditNote (#3): stamp pro.refundTimestamp /
refundedBy / refundAmount unconditionally rather than gated on
totalRefundAmount > 0. Defensive idempotency on the state machine: a
0-amount approve (corner case where the invoice's line items are already
fully returned via a sibling DN flow) used to leave the PRO in pending
state, allowing a second Approve click to issue a duplicate CN at NIC.
rejectReturn non-serialized reversal (#5): the reversal loop was gated
on inventoryItem.serialNumber being non-blank, leaving non-serialized
GOOD items' SALE_RET +1 increments un-reversed on rejection — phantom
warehouse stock. Now mirrors applyReceipt's nonSerialWhItemMap pattern
(orderId|itemId) and reverses both serialized and non-serialized.
Conservative addQuantity(-1) gate retained: only fires when lastScanType
== SALE_RET, matching the prior serialized behaviour. |
|
| 36407 |
16 d 6 h |
amit |
/trunk/profitmandi-dao/src/main/ |
Sale-return reversal: cancellability gate, CN on approve, INV reject, ROI semantics
GstProService.isIrnCancellable(invoiceNumber): predicate extracted from
the inline 24h check used in cancelInvoiceGst, so callers outside the
service can decide branching without duplicating the rule. DC and no-IRN
cases return false — those paths use EWB cancel / credit-note issuance.
PurchaseReturnServiceImpl: split single-phase return-receive into
submitReceiptForApproval + applyReceipt. Submit persists per-item return
type on PurchaseReturnItem so apply (called inline on auto-approve, or
later from refundOrder when finance clicks Process Refund) can replay
the scan loop without the original itemReturnTypes map.
processInvoiceReturn(autoApprove=true) no longer creates a PRO. Routes
through new cancelInvoiceFully which calls gstProService.cancelInvoiceGst
(the canonical IRN-cancel path setting Order.status=INVOICE_CANCELLED)
and adds wallet credit + warehouse-stock restoration. Cancellations now
live on Order/EInvoiceDetails screens, not in the returns ledger —
matches standard ERP practice and the existing cancelInvoiceGst flow.
processInvoiceReturn(autoApprove=false) creates an INV-prefix PRO in
pending state and calls notifyFinanceApprovalPending (Finance L1+L2
emails resolved dynamically from PositionRepository).
approveInvoiceReturn now runs applyInvoiceReturnViaCreditNote — raises
local CreditNote + CreditNoteLine rows (sequential CN# from
SellerWarehouse), issues CRN at GST via generateCreditNoteIrn, restores
warehouse stock, populates ReturnOrderInfo (this path IS a customer
return without DN — ROI is the right anchor), credits wallet. Drops the
old applyInvoiceReturnEffects helper which mishandled both cancel and
return-via-CN as the same path.
rejectInvoiceReturn: new method for finance to reject pending INV PROs.
Sale stands — only stamps reject_timestamp/reject_remark. No inventory,
no wallet, no GST action, no ROI. Closes the gap where finance had
Approve as the only option on a pending INV PRO.
refundOrder gains a refund guard (PRO must exist, not refunded, not
rejected) and applyReceipt-if-needed at the top — Finance's existing
Process Refund button now drives approve+refund atomically.
PurchaseReturnOrderRepository.selectByWarehouseIdsAndDateRange: Hibernate
query for a date-range listing on /return/invoice (default last 30
days, limit 200).
@Transactional(rollbackFor=Exception.class) at class level —
ProfitMandiBusinessException is checked, so Spring's default rollback
didn't fire on guard failures, allowing partial commits. Closing that
silently broken behaviour.
LineItemImei N+1 fix: receiveDebitNoteItems / refundOrder / rejectReturn
each iterated orders calling selectByLineItemId per row. Switched to the
existing batch selectByLineItemIds(List).
Email template finance-receipt-approval-pending.vm and SQL migration
migration_imei_net_margin_modal_api.sql added (registers the
/getImeiNetMarginModal endpoint in dtr.api and grants access to the
roles that currently access /order). |
|
| 36387 |
19 d 7 h |
ranu |
/trunk/ |
code commit for reports section v2 |
|
| 36331 |
22 d 9 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Fix @Cacheable name collision between getSaholicStockList variants
SaholicInventoryServiceImpl:271 and :282 both used @Cacheable(value =
'saholicCISList') on no-arg methods. Spring's default SimpleKey.EMPTY means
both methods shared ONE cache entry — whichever was called first poisoned the
cache for the other, even though they return different filtered sets:
- getSaholicStockList (:272) runs selectWarehouseCisNew — tl.active=1 only
- getSaholicStockListWithoutCatalogMovingStatus (:283) runs
selectWarehouseCisNewWithoutCatalogMovingStatus — includes catalog moving
status join and filters out non-stocked OTHER/SLOWMOVING items
Renamed the second cache to 'saholicCISListWithStatus' so each method uses
its own namespace. Consumers of either method now get their method's actual
result, not a random earlier caller's.
This is a correctness fix (wrong cached data) more than a perf fix, though
it does mean both caches fill independently now (tiny cold-path DB uptick,
already mitigated by 5-min TTL via timeoutCacheManager). |
|
| 36327 |
22 d 12 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ |
Fix currentinventorysnapshot/currentreservationsnapshot deadlock and optimize getFirstBillingDate
- SaholicInventoryServiceImpl: enforce reservation-snapshot → inventory-snapshot
lock order in addReservationCount and reduceReservationCount via explicit
session.flush(); eliminates the hadb1 deadlock recorded 2026-04-20 19:43:24
between these two methods' opposite-order writes.
- SaholicInventorySnapshot: add @DynamicUpdate so UPDATEs only rewrite the
changed column instead of all three — cuts redo/binlog write amplification
and makes deadlock dumps pinpoint the actual business path.
- TransactionRepositoryImpl.getFirstBillingDate: replace filesort-over-all-billed-
orders with MIN(billingTimestamp) via new Order.selectFirstBillingByRetailer
named query (Select tables optimized away). Preserves 2017-01-01 cutoff and
null-for-unbilled-partner semantics.
- Add @Cacheable on redisOneDayCacheManager keyed by fofoId (unless null) so the
8 call sites stop piling up identical SELECTs on the order table — this was
the query pinning Hikari slots at 150-460s each in recent processlist dumps. |
|
| 36316 |
23 d 7 h |
aman |
/trunk/ |
Fix:Migrate legacy Purchase Return flow (Report + Bulk Create + Debit Notes) into FOFO |
|
| 36271 |
29 d 8 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Fix processInvoiceReturn skipping SALE_RET for non-serialized items
processInvoiceReturn was only creating warehouse.scanNew SALE_RET entries
for serialized items (looked up by serial number). Non-serialized items
like accessories were silently skipped, leaving warehouse inventory
unreturned.
Fixed by working directly off SALE scans from warehouse.scanNew instead
of serial number lookup. This handles both serialized and non-serialized
items uniformly. Also uses actual sale quantity instead of hardcoded 1. |
|
| 36147 |
41 d 14 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ |
Add original_invoice_number to credit_note for RETURNS type, increase PrecDocDtls cap to 10
CreditNote entity: added originalInvoiceNumber field
PurchaseReturnServiceImpl: set originalInvoiceNumber on RETURNS CN
CreditNoteServiceImpl: increased invoice ref collection from 4 to 10
GstProService: increased PrecDocDtls limit from 4 to 10 |
|
| 36144 |
42 d 5 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Wire Credit Note on debit note refund — proper CN numbering and persistence
refundOrder(debitNoteId):
- Generate CN number via SellerWarehouse.creditNoteSequence (CN-{prefix}{seq})
- Persist CreditNote record (type=RETURNS) in transaction.credit_note
- Persist CreditNoteLine per returned item with tax rates from original order
- Generate CRN e-invoice IRN on NIC referencing original invoice
- Non-fatal: CN/IRN failure doesn't block the refund |
|
| 36143 |
42 d 5 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Wire Credit Note e-invoice generation on debit note refund
refundOrder(debitNoteId):
- After wallet refund and status updates, generate CRN e-invoice on NIC
- Credit Note number: CN-{debitNoteNumber}
- References original transaction invoice via PrecDocDtls
- Non-fatal: CRN failure doesn't block the refund
- Supports multiple CRNs per invoice (partial returns over time) |
|
| 36142 |
42 d 6 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/ |
Prevent duplicate SALE_RET scans — fix double wallet refund bug
receiveDebitNoteItems():
- Build alreadyReturnedSet from existing SALE_RET/DOA_IN/SALE_RET_UNUSABLE scans
- Serialized: throw exception if IMEI already returned against same order
- Non-serialized: include existing return count in over-return check
processInvoiceReturn():
- Same alreadyReturnedSet check — skip with warning if already returned
Prevents the bug where same IMEI is returned, re-sold, then returned again
against the original order causing duplicate wallet refund. |
|
| 36103 |
44 d 6 h |
amit |
/trunk/profitmandi-dao/src/main/ |
Add DN rejection with full reversal: restore inventory, schemes, price drops, offers; add deny reason to purchase return items; add purchase return notification service |
|