Subversion Repositories SmartDukaan

Rev

Show changed files | Directory listing | RSS feed

Filtering Options

Rev Age Author Path Log message Diff
37845 3 d 1 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)  
37822 6 d 23 h amit /trunk/profitmandi-dao/src/ feat(warehouse): physical warehouse setup service, supplier mapping PO guard, address active flag

- WarehouseSetupService + WarehouseSetupValidator: create seller (state from GSTIN,
unique label/GSTIN), address master (city stored last, 6-digit pin, contact),
physical warehouse (OURS/BAD vendor 40 + Dummy/G + sellerwarehouse + mapping in
one transaction), activate/deactivate (sellerwarehouse.is_active), remap address
with internal store sync. Limits follow column sizes (sql_mode is empty).
- WarehouseAddressMaster.active: only active addresses are offered for assignment.
Migration sql/20261001_warehouseaddressmaster_active.sql (applied on hadb1).
- PO guard: createPurchaseOrder refuses a supplier with no OURS/GOOD vendor
warehouse at the destination (GRN could never receive it).
InventoryWarehouseRepository.hasGoodSupplierWarehouse / selectSupplierIdsWithGoodWarehouse
use existence checks; 67 pairs carry duplicate OURS/GOOD rows.
- SellerService.syncInternalStoreAddress(store); RetailerServiceImpl syncs an
INTERNAL store's address when it moves warehouse or becomes internal.
- Record of 2026-10-01 HR Gurugram setup SQL (seller 21, warehouses 13368/13370/13372).
- Tests: WarehouseSetupValidatorTest (10), WarehouseSetupServiceImplTest (7).
 
37790 10 d 5 h amit /trunk/profitmandi-dao/src/main/ Return refund as B2C when NIC refuses the buyer's GSTIN

A return whose credit note NIC refuses because the BUYER's GSTIN is
cancelled or invalid could not be settled at all: the approval threw, and
with it went the refund, the stock and the return rows (NSUPDL5176, Mobile
Hub, GSTIN 08DCUPD7948K1ZP). Where the invoice itself had never been filed
the return was instead refunded with no credit note at all, leaving the
refund undocumented.

Raising the note automatically is not the answer - it is Finance's call,
and the GST on a cancelled-GSTIN sale is not recoverable, so paying the
full value back loses it. Both flows therefore record the refusal and stop.

GstProService: getIrnFailureReason (NIC's refusal for an invoice),
isInvalidBuyerGstin (that refusal is about the buyer's registration -
deliberately NOT a state-code mismatch, which is a data error to fix and
retry, nor anything naming our own seller GSTIN) and briefIrnReason (one
plain-ASCII line of 128 chars; credit_note is latin1 and sql_mode is empty,
so anything else would store as '?').

PurchaseReturnServiceImpl: both the invoice-return and the debit-note
refund detect that refusal, record it through ReturnIrnFailureRecorder and
throw ReturnIrnGstinFailureException. The recorder commits in REQUIRES_NEW
because the approval it records is about to roll back, and it only inserts -
return_irn_failure carries no foreign key on purpose, since an FK check
would take a shared lock on the very PurchaseReturnOrder row the dying
transaction may still hold.

Finance may then settle the return as B2C for the rest of that calendar day:
refundAsB2c credits the value NET of GST in whole rupees (B2cRefundQuote,
HALF_UP per line, so the line table and the total always agree), restores
the stock and issues a local credit note for exactly that amount with no tax
on its lines, no IRN and NIC's reason recorded. The amount is fixed - the
caller must pass back the quoted figure - and a remark and explicit consent
are required. On a later day the option only reopens after a fresh approval
attempt is refused again, so NIC is always re-checked first.

Mails: every refusal notifies Accounts L2 and above; the B2C settlement
notifies them and the partner's Warehouse L1/L2, both tabulated.

The partner account statement is unaffected: it skips RETURNS notes and
credits returns from returnorderinfo, so the new notes cannot double-credit.

DEPLOY ORDER: apply sql/add_return_b2c_refund_20260921.sql BEFORE any war
built from this dao. CreditNote now maps irn_skip_reason and b2c, so every
credit-note read in web, fofo and cron fails until the columns exist.
Untested beyond compilation.
 
37727 17 d 8 h amit /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/transaction/ Fixed mail sender everywhere  
37600 26 d 23 h amit /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ Replace entity loads with scalar aggregates in the investment sweep

Order.lineItem is a ManyToOne with FetchType.EAGER, so getInTransitOrders() and
selectPendingGrnOrders() pulled ~6,865 Order entities plus a LineItem for each
into the session every two minutes - all dirty-checked at flush - when the sweep
only reads getRetailerId() and getTotalAmount(). That, plus ~1,690 FofoStore and
~984 PartnerInvestment rows, put roughly 17,000 entities in one session per pass
and is most of the ~10s each sweep was taking.

Adds two scalar named queries returning (retailerId, sum(totalAmount)) grouped by
partner. A projection never hydrates the entity, so the eager association never
fires - about 13,700 entities become ~1,000 rows. The predicates copy
selectOrders(ids, pendingOrderStatus) and selectPendingGrnOrders(ids) exactly,
including the SD_START_DATE floor, and the comment on the named queries says to
change them together.

Deliberately NOT done by making lineItem lazy: that mapping is shared by every
Order consumer in the codebase and flipping it globally is a far wider change than
this needs.

Entity-returning variants are untouched for their existing callers. Drops the now
unused sumOrderAmounts helper and the TransactionService dependency.

Not a fix for a problem - the sweep was comfortably inside its 120s window at ~8%
duty. It removes waste that would matter if the cadence were ever shortened.
 
37588 27 d 2 h amit /trunk/profitmandi-dao/src/main/ Serve partner investment from a 2-minute snapshot instead of a 3-hour cache

getInvestment() was @Cacheable on a 3-hour Redis cache that addAmountToWallet
evicted but consumeAmountFromWallet did not. A partner whose advance payment was
swept straight to a loan had the money counted twice - once as a still-cached
wallet balance, once as the reduced utilisation - overstating their credit limit
by the payment x their tier until the cache expired.

Replaced with fofo.partner_investment, refreshed every 2 minutes by
PartnerInvestmentSweepService. Every coupled term is read in one pass, so wallet
and utilisation (and in-stock and aged-Apple) can never come from different
moments. A shorter TTL would only have made the error rarer - it scales with the
payment, not the delay.

- PartnerInvestment entity/repository + partner_investment_snapshot.sql
- PartnerInvestmentSweepService: 9 batched reads, stores base_value for change
detection, refreshes aged-Apple for partners whose stock moved intra-day
- getInvestment/getInvestmentsForFofoStores both read the snapshot, so the two
paths no longer disagree; live compute retained as fallback
- selectActivatedStockAmountByFofoIds: batches an N+1 that cost 233ms x 1690
partners (6.6 min -> 1.0 s)
- getFirstBillingDates: batches another N+1 (4.6 s -> 0.67 s)
- selectPendingGrnOrders(List) now applies the same SD_START_DATE floor as the
single-partner overload; the two were reporting different GRN-pending
- selectPartnerStockValueMap takes excludeActivated: an activated Apple handset
held past the aging window was added once to in-stock and subtracted twice
(activated stock, then the aged haircut). 90 units, 24 partners, Rs 65.19 lakh
double-deducted. Live-demo passes false - no overlap there.
- applyManualAdjustment: routes the two hand-rolled admin wallet adjustments
through WalletServiceImpl so they take the FOR UPDATE lock
- add_idx_order_grn_pending.sql: covering index, GRN query 1320ms -> 514ms
 
37323 52 d 3 h 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 52 d 4 h 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.
 
37274 59 d 9 h amit /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ Freeze margin-scheme purchase price on the invoice line

Refurbished (GST Rule 32(5)) lines re-derived their purchase price by serial on
every read, resolving to the LATEST warehouse.inventoryItem row. A returned
device gets re-GRNed, sometimes at a different price, so a credit note or a
regenerated PDF could reverse a margin the invoice never charged. 11 already-
billed lines resolved to a price they were not sold at; IMEI 353917853695268
has been sold on six invoices at two different purchase prices.

InvoiceService.freezeMarginPurchasePrices now stamps the value onto
transaction.lineitem.margin_purchase_price at billing time (saveInvoice step 0,
inside the billing transaction), and resolveMarginPurchasePrice reads the frozen
value thereafter, falling back to the live lookup only when null so pre-existing
lines behave exactly as before.

Requires the column from db-scripts/add_margin_purchase_price_column.sql, which
must be applied before this is deployed.
 
37089 86 d 5 h amit /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/ Optimize partnerPerformance data access: fofoId-scoped + month-bucketed query variants

- Order: fofoId-scoped billing-avg named queries (replace all-partner scan+filter)
- MonthlyTarget: selectByDatesAndFofoId batches 7 per-month lookups into one
- SchemeInOut/OfferPayout: month-bucketed ...ByMonth earnings queries collapsing the
per-month loop; new MonthlyBrandIncomeModel / MonthlyOfferPayoutModel
All additive; existing shared queries and their callers unchanged.
 
37077 86 d 8 h ranu /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/transaction/ old version app disabled for rbm  
36999 98 d 2 h amit /trunk/profitmandi-dao/src/main/ Price-hike deduction (self-contained): revert hike logic from price-drop flow + remove deduct_on_hike flag; add GRN hook (PurchaseServiceImpl, before schemes) and on-demand executor endpoint that debit under-charged units billed in the hike's [affected_on, created_on] window. Idempotent per (hike, imei).  
36977 99 d 6 h amit /trunk/profitmandi-dao/src/main/ Price-hike deduction: add deduct_on_hike flag; process flagged hikes as symmetric mirror of drops (wallet debit + scheme reverse/recompute); remove getPayouts price-increase clamp so hikes raise scheme/offer margin  
36974 99 d 7 h ranu /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/transaction/ changeList  
36972 99 d 7 h ranu /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/ changeList  
36958 100 d 5 h amit /trunk/profitmandi-dao/src/main/ Flagship credit: fire interest-free limits at billing + per-IMEI conversion

- createLoanForBilling now detects flagship lines inside the billing transaction (fixes the
REQUIRES_NEW visibility bug where flagship detection re-queried uncommitted invoice_number and
never fired). Creates one combined flagship limit (is_flagship=1, limit_block=1, 30-day deadline)
plus one transaction.loan_imei row per device.
- convertFlagshipOnSale / IMEI activation now convert only the sold device's slice (matched by IMEI),
so same-model siblings and other billing tranches keep their interest-free window; full convert at
30-day expiry. Lock order aligned (loan -> loan_imei) to avoid sale/expiry deadlock.
- New transaction.loan_imei table + LoanImei entity/repository (migration_loan_imei_table.sql).
- selectAllLoansByInvoice: PurchaseReturn now settles BOTH the real loan and the flagship limit on a
flagship-invoice return (prevents credit leak from a stranded limit).
- Cap guard (flagship credit never exceeds amount drawn) and robust limit settlement (paisa threshold
instead of exact float equality).
 
36943 104 d 3 h amit /trunk/profitmandi-dao/src/main/ hdfc_payment: add credited flag to fix blocked manual add-money approval

Since r36927 the HDFC push-credits flow captures every payment into
hdfc_payment BEFORE validating the virtual account, so VA-missing/unmatched
rows are stored uncredited. The manual add-money approval guarded on mere
row existence, wrongly blocking these recoverable payments.

Add a credited flag (default false) set true only when a wallet credit
actually happens. Includes migration + backfill (reference=id AUTOMATED_ADVANCE
match, plus pre-r36927 rows credited by construction).
 
36817 120 d 5 h amit /trunk/profitmandi-dao/src/main/ Link returnorderinfo to credit_note via credit_note_id FK

Add a direct credit_note_id column on returnorderinfo so a return row
can be tied to the Credit Note it was refunded via, replacing the
indirect/ambiguous association through original_invoice_number + the CN
number embedded in refundDescription. Stamped in
applyInvoiceReturnViaCreditNote; migration adds the column and backfills
existing rows by parsing the CN number out of refundDescription.
 
36774 126 d 8 h amit /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/ Add bulk getLoanOutstandingAtDate (principal+interest per partner at a date) for account reco closing  
36754 128 d 8 h amit /trunk/ Account statement (Excel): reconcile running balance to net standing (wallet + pending indent - loan).

- populateData: categorised lines, scheme/margin shown as month-end MARGINS credit note (CN_CANCELLATION and negative-net CNs rendered as debit notes), interest-accrued line as the standing-moving loan cost, and a net-pending-indent/diff line that lands the running balance on closing.
- Returns shown individually from returnorderinfo (one credit line per return, against its invoice on refundedAt); billing-query RETURNED/RETURNS_CN suppressed to avoid double count.
- Exclude PURCHASE and CREDIT_LIMIT/CREDIT_UTILIZED (loan cash legs) from the wallet body.
- LoanStatementRepository.getInterestAccruedBetween; ReturnOrderInfoRepository.selectReturnsBetween.
 

Show All