| Rev |
Age |
Author |
Path |
Log message |
Diff |
| 36376 |
9 m |
aman |
/trunk/ |
Feat:Cart Api Implementation |
|
| 36375 |
1 h 17 m |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ |
Added Rising Star/NEW |
|
| 36374 |
1 h 30 m |
ranu |
/trunk/ |
schemes and offer for v2 version |
|
| 36373 |
3 h 53 m |
ranu |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/monitors/ |
login talktime hours cap on 100% |
|
| 36372 |
4 h 7 m |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/ |
Wallet: SELECT FOR UPDATE on user_wallet mutations to close lost-update hole
addAmountToWallet/consumeAmountFromWallet(x2)/rollbackAmountFromWallet all
follow a read-modify-write pattern on user_wallet with no pessimistic lock
and no @Version, so two concurrent tx for the same partner both read the
same pre-snapshot amount, compute their own deltas, and commit - the second
UPDATE silently overwrites the first's credit/debit. user_wallet_history
still gets both rows, so balance drifts vs sum(history) with no exception.
Replaces the misnamed (and body-broken) selectByIdForUpdate - whose
implementation was a plain selectById, not a lock - with a new
selectByRetailerIdForUpdate that issues SELECT ... FOR UPDATE via
LockModeType.PESSIMISTIC_WRITE, mirroring the idiom already used in
GenericRepositoryImpl.selectByIdForUpdate and OrderRepositoryImpl.
Preserves the create-on-missing behavior of selectByRetailerId so
first-time partners keep working.
Switches the four read-modify-write call sites in WalletServiceImpl from
selectByRetailerId to the new locking variant. Read-only callers
(getUserWalletByUserId, getUserWalletHistoryByUserId, etc.) keep using
the non-locking selectByRetailerId - MVCC snapshot reads stay non-blocking
for display/statement endpoints.
Also drops the stale commented-out selectByIdForUpdate line in
rollbackAmountFromWallet and removes the broken method from the
UserWalletRepository interface / impl - it had zero live callers.
Blast radius: every write call to these three wallet methods now holds
an X-lock on the target user_wallet row for the rest of the outer tx.
Concurrent write tx for the same partner will briefly serialize at the
SELECT FOR UPDATE - correct serialization instead of silent drift.
Read-only traffic is unaffected (MVCC). |
|
| 36371 |
4 h 43 m |
amit |
/trunk/ |
HDFC webhook: INSERT IGNORE on hdfc_payment to fix concurrent-duplicate 500 storm
Replaces persist() with a native INSERT IGNORE so concurrent same-UTR webhook
retries serialize on the unique-index check, and the loser gets a 0-row no-op
(warning, not exception). Outer @Transactional session stays clean, Spring
commits normally, HDFC sees 200 on both the winner (Success) and the loser
(Duplicate) - retry amplification ends.
Flow:
persist(hdfcPayment) -> insertIgnore(hdfcPayment) + selectByUtrNo(utr)
- inserted == 1: proceed with wallet / sidbi side-effects using fetched id
- inserted == 0: respond Duplicate, skip side-effects (owned by winning tx)
- defensive: log warn if insertIgnore returned 0 but selectByUtrNo finds
no row (could mean IGNORE swallowed a non-duplicate issue like truncation)
Also drops HdfcProcessingHelper (r36366) which used REQUIRES_NEW for the same
goal; that approach required a second JDBC connection and is no longer needed
with SQL-level idempotency.
Does NOT touch the wallet-side lost-update hole (user_wallet read-modify-write
without FOR UPDATE). That is a separate commit. |
|
| 36370 |
17 h 17 m |
vikas |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
Fix: App login |
|
| 36369 |
21 h 6 m |
vikas |
/trunk/profitmandi-fofo/src/main/ |
Fix: Sale purchase invoice item quantity calculation |
|
| 36368 |
22 h 35 m |
aman |
/trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/ |
Fix:Update Timeline Title |
|
| 36367 |
23 h 46 m |
amit |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/hdfc/ |
HDFC webhook: delegate writes to HdfcProcessingHelper; always respond OK
Fixes the concurrent-duplicate deadlock observed on hadb1 2026-04-23 12:54:11
(two HDFC retries inserting same utr='308490624083' → InnoDB deadlock →
LockAcquisitionException → 500 → HDFC retries again → amplification).
- addPayment: the HDFC row build + persist + wallet/sidbi is now a single call
to hdfcProcessingHelper.processPayment() which runs in REQUIRES_NEW. The
helper catches DataIntegrityViolationException and logs silently; our tx
is unaffected.
- The else branch (pre-select found an existing row) now returns the same
code=100 status=Success as the main path instead of code=200 Duplicate.
Per product direction: HDFC should see 'OK' regardless of whether the row
already existed from a prior webhook, manual entry, or reconciliation —
retries stop cleanly, no 'Duplicate' surface distinction.
Did NOT add @Transactional(readOnly=true) on the outer method despite its
read-heavy shape — checkManualPayments() at line 277 has a write side-effect
(rejecting pending manual wallet requests for the same utr) which would be
silently dropped in a read-only session. Kept class-level writable tx for
the outer; only HDFC writes moved to REQUIRES_NEW helper. |
|
| 36366 |
23 h 46 m |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/ |
Add HdfcProcessingHelper: per-payment REQUIRES_NEW wrapper for HDFC credit writes
Isolates the hdfc_payment insert + wallet-credit / sidbi-sanction writes in
their own transaction so concurrent duplicate webhooks (HDFC retry, manual
entry, reconciliation) can't poison the caller's session. On the deadlock/
duplicate-key path (DataIntegrityViolationException), logs once at INFO and
returns silently — the row's side-effects are owned by whichever path
inserted it first; re-applying would double-credit.
Mirrors the OfferProcessingHelper pattern (also REQUIRES_NEW per item),
keeping the controller's outer transaction clean and making this method
safe to invoke from a batch loop later without refactor. |
|
| 36365 |
23 h 54 m |
vikas |
/trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ |
Homepage API |
|
| 36364 |
1 d 2 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/fofo/ |
Fix /activateFinanceServices returning empty row for retailers without partner_onboarding_panel
Change selectFinanceServicesByFofoId named query to LEFT JOIN PartnerOnBoardingPanel.
Previously an inner join filtered out 32 fofo_stores (16 internal + 16 external)
lacking an onboarding panel row, so the /activateFinanceServices response rendered
empty for them (e.g. codeInt=1359 / UPGBN1359) even though the partner_service
save itself worked. |
|
| 36363 |
1 d 21 h |
amit |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
Idempotent fofo_order creation in UpSaleController (mirrors r36362 in dao)
Same change as OrderServiceImpl.createAndGetFofoOrder: pre-select by
(fofo_id, invoice_number) and catch DataIntegrityViolationException as the
slow-race fallback. Paired with uk_fofo_order_fofo_invoice unique key. |
|
| 36362 |
1 d 21 h |
amit |
/trunk/profitmandi-dao/src/main/ |
Make fofo_order creation idempotent on (fofo_id, invoice_number)
Fixes insert-intention gap-lock deadlocks on idx_invoice_number observed in
SHOW ENGINE INNODB STATUS at 2026-04-22 13:01:54 — two concurrent requests
inserting the same invoice_number for the same customer (client retry /
upstream webhook retry pattern).
- OrderServiceImpl.createAndGetFofoOrder: select-then-insert idempotency.
Fast path returns existing row if already created; slow-race path catches
DataIntegrityViolationException and re-selects the winner's row.
- add_uk_fofo_order_fofo_invoice.sql: adds UNIQUE KEY (fofo_id, invoice_number)
so the loser of a concurrent-insert race gets a clean DIVE instead of a
silent duplicate row (pre-check showed zero existing dup groups, safe).
findExistingFofoOrder wraps the repo call to swallow the repo's declared
ProfitMandiBusinessException — the impl actually returns null on not-found
(constructs an exception but never throws), so the swallow matches reality. |
|
| 36361 |
1 d 21 h |
amit |
/trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ |
Switch @Scheduled updatePartnerLimit to batch-tracked version. Was calling legacy scheduledTasks.updatePartnerLimit (one synchronized tx, writes to all ~1500 partners each run, no audit). Now calls batchScheduledTasks.updatePartnerLimitWithBatch (writes only changed partners in per-partner REQUIRES_NEW, records each run in cron_batch / cron_batch_item, sends failure email on partial failures). Same cadence (every 20 min), same business logic. Runs are now visible in /admin/cron-batches UI. |
|
| 36360 |
1 d 22 h |
ranu |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/monitors/ |
login talktime hours cap on 100% |
|
| 36359 |
1 d 22 h |
ranu |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/ |
rbm rating dashboard view commited |
|
| 36358 |
1 d 22 h |
amit |
/trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/ |
Replace non-ASCII separators in cron-batches modal with ASCII. Title middle-dot (U+00B7) and empty-timestamp em-dash (U+2014) were rendering as mojibake ('·' and 'â€') — response was being served without charset=UTF-8 in the Content-Type header despite Velocity being UTF-8 configured. Swapped to '|' and '-' to avoid the encoding issue without chasing it through Velocity/Tomcat config. |
|
| 36357 |
1 d 23 h |
amit |
/trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/ |
Fix background-thread 'no session' error in DB guard. CronBatchRepository.selectRunningForOffer uses getCurrentSession() which needs an open tx; when OfferBatchService.processOfferWithBatch is called from the async worker thread (no outer tx), the guard query crashed with 'Could not obtain transaction-synchronized Session'. Offer 8819 submit succeeded but the background run died at the guard — before createBatch, so no cron_batch / cron_batch_item rows. Added CronBatchService.findRunningForOffer wrapping the repo call in @Transactional(readOnly=true); orchestrator calls the service method instead of repo directly. Matches the pattern used by loadOfferRequest / createBatch / calculate*Payouts — every caller opens its own tx. |
|