<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>SmartDukaan &#x2013; /</title><description>WebSVN RSS feed &#x2013; SmartDukaan</description><lastBuildDate>Sat, 19 Sep 2026 16:13:46 +0530</lastBuildDate><generator>WebSVN 2.8.6-DEV</generator><language>en</language><link>https://svn.smartdukaan.com/log.php?repname=SmartDukaan&amp;path=%2F&amp;max=40&amp;peg=37604</link><atom:link href="https://svn.smartdukaan.com/rss.php?path=%2F&amp;peg=37604&amp;repname=SmartDukaan" rel="self" type="application/rss+xml" />
<item><pubDate>Sat, 12 Sep 2026 17:00:50 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37604 – Show the derived movement price when building an internal purchase ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;Show the derived movement price when building an internal purchase order&lt;br /&gt;
&lt;br /&gt;
Both places a price reaches a purchase order now use the movement price for internal&lt;br /&gt;
suppliers: the single lookup as an item is added on screen, and the per-item resolution&lt;br /&gt;
behind a bulk upload, which does the whole file in one pass instead of loading a circular&lt;br /&gt;
the sending warehouse does not have.&lt;br /&gt;
&lt;br /&gt;
Removes addVendorPricingIfMissing, which fired only when someone typed a numeric item id&lt;br /&gt;
into the search box, and only for Samsung or non-handsets, writing permanent approved&lt;br /&gt;
pricing rows onto the internal supplier from a hardcoded source vendor. Bulk upload never&lt;br /&gt;
called it at all, which is why the same item could be added on screen but rejected in a&lt;br /&gt;
file.&lt;br /&gt;
&lt;br /&gt;
Tests cover what is decided once origins are known - drawing the oldest stock first,&lt;br /&gt;
refusing a quantity that spans two original vendors while naming how many can move and&lt;br /&gt;
asking for a separate order, refusing an unmapped supplier, and falling back to the catalog&lt;br /&gt;
without ever recording an inferred vendor as though it were known.&lt;br /&gt;
&lt;br /&gt;
Requires profitmandi-dao r37603.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/VendorController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/warehouse/PurchaseOrderController.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/service/warehouse&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/service/warehouse/InternalMovementPricingServiceTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37604&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37604&amp;peg=37604</guid></item>
<item><pubDate>Sat, 12 Sep 2026 17:00:04 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37603 – Price internal warehouse movements from the stock&apos;s original vendor  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 11 file(s) modified&lt;/strong&gt;&lt;br/&gt;Price internal warehouse movements from the stock&apos;s original vendor&lt;br /&gt;
&lt;br /&gt;
Stock moving between our own warehouses was priced from the sending internal supplier&apos;s&lt;br /&gt;
own vendor catalog, which only ever holds prices copied from elsewhere - so every hop let&lt;br /&gt;
the price drift further from what the group actually paid, and a movement was blocked&lt;br /&gt;
outright whenever that supplier happened to have no row for the item.&lt;br /&gt;
&lt;br /&gt;
It is now derived from the stock being moved: the original EXTERNAL vendor is established&lt;br /&gt;
per unit and that vendor&apos;s current catalog price is used. Origin is looked for in&lt;br /&gt;
descending order of certainty - the serial traced back to the external purchase that first&lt;br /&gt;
brought the unit in, then the unit&apos;s own inbound PO when that was external, both of which&lt;br /&gt;
are facts that survive any number of internal hops. Non-serialised stock that has already&lt;br /&gt;
moved internally has no recoverable origin at all, since fungible units carry no identity&lt;br /&gt;
and the movement records nothing linking the receiving row to its source, so those fall&lt;br /&gt;
back to the most recent externally approved price for the catalog and are never recorded&lt;br /&gt;
as though their vendor were known.&lt;br /&gt;
&lt;br /&gt;
A purchase order carries one price per item, so an item can only move from one original&lt;br /&gt;
vendor at a time. Where a requested quantity would run past the oldest vendor&apos;s stock into&lt;br /&gt;
another&apos;s, this refuses and reports how many can move now and at what price, leaving the&lt;br /&gt;
second order to whoever is moving the stock, rather than averaging the two or silently&lt;br /&gt;
splitting the order. Each order therefore stays attributable to one vendor.&lt;br /&gt;
&lt;br /&gt;
Receiving no longer validates price for these movements: both sides of the comparison come&lt;br /&gt;
from the same derivation, so a mismatch cannot mean anything. That also removes a null&lt;br /&gt;
dereference in GrnRequestServiceImpl, which assumed every supplier has a circular.&lt;br /&gt;
&lt;br /&gt;
Removes addVendorPricingIfMissing, which wrote permanent approved pricing rows onto internal&lt;br /&gt;
suppliers sourced from hardcoded vendor 334 for Samsung or an arbitrary findFirst() vendor&lt;br /&gt;
otherwise, stamped with hardcoded auth ids. Those rows are now not just unnecessary but&lt;br /&gt;
harmful: they would pin a stale price that wins over the derived one.&lt;br /&gt;
&lt;br /&gt;
Verified against live data: covers every unit in every warehouse with none unresolved,&lt;br /&gt;
agrees exactly with the origin join the FOCO/ImeiSupplierPricing report already runs in&lt;br /&gt;
production, and prices 12,305 of 13,589 units within 2% of what was actually paid.&lt;br /&gt;
Resolution takes 0.7ms for one item and 1.1ms for ten.&lt;/div&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/model/InternalMovementAllocationModel.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/model/InternalMovementPriceModel.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/inventory/VendorCatalogPricingLogRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/inventory/VendorCatalogPricingLogRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/warehouse/WarehouseInventoryItemRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/warehouse/WarehouseInventoryItemRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/GrnRequestServiceImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/InternalMovementPricingService.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/InternalMovementPricingServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/InvoiceServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/PurchaseOrderServiceImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37603&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37603&amp;peg=37604</guid></item>
<item><pubDate>Sat, 12 Sep 2026 14:51:26 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37602 – Remove no-op refreshSnapshotAgeing task; restore originalInventoryItemId backfill call  refreshSnapshotAgeing ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Remove no-op refreshSnapshotAgeing task; restore originalInventoryItemId backfill call&lt;br /&gt;
&lt;br /&gt;
refreshSnapshotAgeing ran every 30 minutes aggregating warehouse.inventoryItem.rootInvoiceDate,&lt;br /&gt;
a column nothing ever wrote, so its UPDATE ... JOIN matched zero rows on every run and&lt;br /&gt;
currentinventorysnapshot.oldest_invoice_date was never populated on any of 11,686 rows.&lt;br /&gt;
Removed along with the sessionFactory field it was the only consumer of.&lt;br /&gt;
&lt;br /&gt;
Application.java had migrations.migrateWarehouseOriginalInventoryItemId(batchSize) commented&lt;br /&gt;
out while still logging &apos;Starting migration...&apos; and &apos;Migration completed.&apos;, so&lt;br /&gt;
--migrateOriginalInventoryItemId reported success while doing nothing. Restored the call;&lt;br /&gt;
it remains opt-in via the CLI flag and cannot fire on its own.&lt;br /&gt;
&lt;br /&gt;
Requires profitmandi-dao r37601 (entity fields removed).&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/Application.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ScheduledTasks.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37602&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37602&amp;peg=37604</guid></item>
<item><pubDate>Sat, 12 Sep 2026 14:51:19 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37601 – Remove dead stock-ageing fields rootInvoiceDate and oldest/newest_invoice_date  rootInvoiceDate on ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;Remove dead stock-ageing fields rootInvoiceDate and oldest/newest_invoice_date&lt;br /&gt;
&lt;br /&gt;
rootInvoiceDate on WarehouseInventoryItem had no writer anywhere in the codebase and&lt;br /&gt;
was read only by ScheduledTasks.refreshSnapshotAgeing(), which therefore matched zero&lt;br /&gt;
rows on every 30-minute run. oldest/newest_invoice_date on SaholicInventorySnapshot&lt;br /&gt;
were written only by that task and read by nothing. Verified on prod: null on all&lt;br /&gt;
1,528,669 inventoryItem rows and all 11,686 snapshot rows respectively.&lt;br /&gt;
&lt;br /&gt;
Stock ageing that is actually in use resolves the original external supplier at query&lt;br /&gt;
time by serialNumber + supplier.internal = false, and does not read these columns.&lt;br /&gt;
originalInventoryItemId is deliberately left alone - it is populated on 157,020 rows.&lt;br /&gt;
&lt;br /&gt;
Includes sql/drop_dead_ageing_columns_20260912.sql to drop the columns. Run it only&lt;br /&gt;
after web, fofo and cron are all on this build.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/inventory/SaholicInventorySnapshot.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/warehouse/WarehouseInventoryItem.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/drop_dead_ageing_columns_20260912.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37601&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37601&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 20:40:13 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37600 – Replace entity loads with scalar aggregates in the investment sweep ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;Replace entity loads with scalar aggregates in the investment sweep&lt;br /&gt;
&lt;br /&gt;
Order.lineItem is a ManyToOne with FetchType.EAGER, so getInTransitOrders() and&lt;br /&gt;
selectPendingGrnOrders() pulled ~6,865 Order entities plus a LineItem for each&lt;br /&gt;
into the session every two minutes - all dirty-checked at flush - when the sweep&lt;br /&gt;
only reads getRetailerId() and getTotalAmount(). That, plus ~1,690 FofoStore and&lt;br /&gt;
~984 PartnerInvestment rows, put roughly 17,000 entities in one session per pass&lt;br /&gt;
and is most of the ~10s each sweep was taking.&lt;br /&gt;
&lt;br /&gt;
Adds two scalar named queries returning (retailerId, sum(totalAmount)) grouped by&lt;br /&gt;
partner. A projection never hydrates the entity, so the eager association never&lt;br /&gt;
fires - about 13,700 entities become ~1,000 rows. The predicates copy&lt;br /&gt;
selectOrders(ids, pendingOrderStatus) and selectPendingGrnOrders(ids) exactly,&lt;br /&gt;
including the SD_START_DATE floor, and the comment on the named queries says to&lt;br /&gt;
change them together.&lt;br /&gt;
&lt;br /&gt;
Deliberately NOT done by making lineItem lazy: that mapping is shared by every&lt;br /&gt;
Order consumer in the codebase and flipping it globally is a far wider change than&lt;br /&gt;
this needs.&lt;br /&gt;
&lt;br /&gt;
Entity-returning variants are untouched for their existing callers. Drops the now&lt;br /&gt;
unused sumOrderAmounts helper and the TransactionService dependency.&lt;br /&gt;
&lt;br /&gt;
Not a fix for a problem - the sweep was comfortably inside its 120s window at ~8%&lt;br /&gt;
duty. It removes waste that would matter if the cadence were ever shortened.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/transaction/Order.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/transaction/OrderRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/transaction/OrderRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/PartnerInvestmentSweepService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37600&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37600&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 20:09:50 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37599 – Reuse the managed snapshot row in the sweep instead of ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Reuse the managed snapshot row in the sweep instead of building a second instance&lt;br /&gt;
&lt;br /&gt;
Every sweep after the first failed with &apos;A different object with the same&lt;br /&gt;
identifier value was already associated with the session :&lt;br /&gt;
PartnerInvestment#107198&apos; and wrote nothing.&lt;br /&gt;
&lt;br /&gt;
selectByFofoIds returns managed entities. The loop then constructed a fresh&lt;br /&gt;
PartnerInvestment for the same id and called saveOrUpdate on it, which Hibernate&lt;br /&gt;
rejects. Sweep one survived only because the table was empty, so no row was&lt;br /&gt;
managed - the failure could not appear until a second run.&lt;br /&gt;
&lt;br /&gt;
Now mutates the row already in the session when there is one, falling back to a&lt;br /&gt;
new instance only for partners with no snapshot. The previous base and gross stock&lt;br /&gt;
are captured before mutation, since comparing the row against itself afterwards&lt;br /&gt;
would report nothing as ever changed.&lt;br /&gt;
&lt;br /&gt;
persist() is kept: a no-op for the managed rows (dirty checking flushes them), and&lt;br /&gt;
still the INSERT for partners appearing between sweeps.&lt;br /&gt;
&lt;br /&gt;
Drops baseDiffersFrom(), now unused - the comparison is against the captured prior&lt;br /&gt;
value, still rounded to paise by the setter on both sides.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/fofo/PartnerInvestment.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/PartnerInvestmentSweepService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37599&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37599&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 19:57:29 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37598 – Add missing @Transactional to the investment sweep  The sweep ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Add missing @Transactional to the investment sweep&lt;br /&gt;
&lt;br /&gt;
The sweep failed on every run with &apos;Could not obtain transaction-synchronized&lt;br /&gt;
Session for current thread&apos; and wrote nothing. BatchScheduledTasks deliberately&lt;br /&gt;
carries no class-level @Transactional - each partner gets its own via REQUIRES_NEW&lt;br /&gt;
in the helper beans - so the sweep ran outside a transaction and&lt;br /&gt;
sessionFactory.getCurrentSession() threw at the first repository call.&lt;br /&gt;
&lt;br /&gt;
PartnerLimitHelper already does this correctly with @Transactional(readOnly=true)&lt;br /&gt;
on its read phase; the sweep simply did not mirror it. Compilation cannot catch&lt;br /&gt;
this - only a run can.&lt;br /&gt;
&lt;br /&gt;
sweep() and refreshAgedStockDaily() both read and write, so they take a read-write&lt;br /&gt;
transaction. Annotations sit on the service rather than the caller because&lt;br /&gt;
BatchScheduledTasks is intentionally non-transactional, and the service is a&lt;br /&gt;
separate bean so the proxy applies.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/PartnerInvestmentSweepService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37598&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37598&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 19:55:40 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37597 – Register /agedAppleImeis for the partner role  RoleInterceptor authorises every ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Register /agedAppleImeis for the partner role&lt;br /&gt;
&lt;br /&gt;
RoleInterceptor authorises every non-admin request through&lt;br /&gt;
RoleManager.isAuthorizedURI(), which regex-matches the URI against dtr.api rows&lt;br /&gt;
reachable via dtr.role_api and throws GE_1004 when nothing matches. The new&lt;br /&gt;
aged-Apple IMEI endpoint (r37593) had no row, so partners would have been denied -&lt;br /&gt;
the Java change alone does not expose an endpoint.&lt;br /&gt;
&lt;br /&gt;
Adds the api row and links it to FOFO, mirroring /activatedImeis (id 215) and&lt;br /&gt;
/activated-imeis-grn-pending (id 285). FOFO_ADMIN needs no row because isAdmin()&lt;br /&gt;
short-circuits before the lookup.&lt;br /&gt;
&lt;br /&gt;
Applied to hadb1: api id 330, linked to role FOFO. Both inserts are guarded by&lt;br /&gt;
NOT EXISTS so the script is safe to re-run per environment.&lt;/div&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/register_aged_apple_imeis_api.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37597&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37597&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 19:43:21 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37596 – Mirror the gateway sanction when a hard limit is released ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Mirror the gateway sanction when a hard limit is released&lt;br /&gt;
&lt;br /&gt;
/resetHardLimit set hard_limit=false and reverted credit_limit to suggested_limit&lt;br /&gt;
but never touched dtr.credit_account, so the SIDBI/SDDIRECT gateway kept the old&lt;br /&gt;
pinned sanction until some later full limit pass rewrote it. Releasing a hard&lt;br /&gt;
limit can move the number a long way - RJAMR501 Inder Mobile is pinned at 800,000&lt;br /&gt;
against a suggested 909,114, so the gateway would under-report him by 109,114.&lt;br /&gt;
&lt;br /&gt;
This was previously masked rather than absent: the 20-minute pass rewrote ~220&lt;br /&gt;
partners every run because float noise made almost every comparison look like a&lt;br /&gt;
change, which repaired the mirror by accident. Rounding that comparison to paise&lt;br /&gt;
(r37589) removed the accidental repair and moving the full pass to daily (r37595)&lt;br /&gt;
stretched the window to most of a day, so the gap is now worth closing properly.&lt;br /&gt;
&lt;br /&gt;
Mirrors sanctioned/available in the same request, matching what&lt;br /&gt;
/creditRequirement already does, and stamps update_timestamp so the change is&lt;br /&gt;
visible as a real limit movement.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/SDCreditController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37596&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37596&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 19:24:56 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37595 – Move the full partner-limit pass from every 20 minutes to ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Move the full partner-limit pass from every 20 minutes to daily&lt;br /&gt;
&lt;br /&gt;
The 2-minute sweep already recalculates the limit for every partner whose base&lt;br /&gt;
moved, which covers investment and utilisation - the inputs that actually change.&lt;br /&gt;
The full 980-partner rescan only exists for inputs base cannot see: credit risk,&lt;br /&gt;
the SIDBI floor and hard_limit.&lt;br /&gt;
&lt;br /&gt;
Those move on a far slower clock. RISK_DECREASE_DAYS_THRESHOLD is 90 days, and&lt;br /&gt;
transaction.fofo_sidbi_sanction has had no new row since Oct 2024 and no recorded&lt;br /&gt;
settlement. Running the rescan 72 times a day to catch them was 71 wasted passes.&lt;br /&gt;
&lt;br /&gt;
Folded into the existing daily job, after the aged-stock refresh so the limit pass&lt;br /&gt;
sees haircuts for partners whose Apple or demo stock crossed its threshold&lt;br /&gt;
overnight. Leaves two scheduled jobs instead of three.&lt;br /&gt;
&lt;br /&gt;
Limit latency is unaffected - that is the 2-minute sweep&apos;s job and it is unchanged&lt;br /&gt;
(~3 partners per window show a changed base, peak 18). The --updatePartnerLimitWithBatch&lt;br /&gt;
CLI entrypoint is untouched for manual runs.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ScheduledSkeleton.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37595&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37595&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 19:22:09 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37594 – Format activated-stock amounts as currency on the dashboard banners  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Format activated-stock amounts as currency on the dashboard banners&lt;br /&gt;
&lt;br /&gt;
Both banners rendered the raw float - &apos;112682.0&apos; instead of a formatted amount -&lt;br /&gt;
because the value sat in a plain &amp;lt;strong&gt; with no currency class, so&lt;br /&gt;
common.js formatCurrency() never picked it up. The sibling&lt;br /&gt;
dashboard-grn-pending-activated-imeis.vm already had the class, which is why one&lt;br /&gt;
banner formatted and the one above it did not.&lt;br /&gt;
&lt;br /&gt;
No jsVersion bump needed: template-only change, no JS or CSS touched.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/analysis-dashboard-activated-imeis.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/dashboard-activated-imeis.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37594&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37594&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 19:19:53 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37593 – Show partners their aged Apple stock and why it lowers ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 7 file(s) modified&lt;/strong&gt;&lt;br/&gt;Show partners their aged Apple stock and why it lowers their credit limit&lt;br /&gt;
&lt;br /&gt;
Apple handsets held past 30 days are deducted when the credit limit is&lt;br /&gt;
calculated, but nothing told the partner - they saw a limit drop with no&lt;br /&gt;
explanation. Adds a dashboard banner alongside the existing &apos;activated but not&lt;br /&gt;
billed&apos; one, shown only when the partner actually has such stock (70 of 980&lt;br /&gt;
today), with the unit count, the value, and View Imeis for the detail.&lt;br /&gt;
&lt;br /&gt;
- dashboard-aged-apple-stock.vm, parsed in dashboard1.vm under&lt;br /&gt;
  #if($investments.aged_apple_qty &gt; 0)&lt;br /&gt;
- count and value both read from the maintained partner_investment snapshot, so&lt;br /&gt;
  the banner never runs its own query and always matches the amount the limit is&lt;br /&gt;
  actually reduced by&lt;br /&gt;
- amount wrapped in &amp;lt;span class=&quot;currency&quot;&gt; so common.js formatCurrency() renders&lt;br /&gt;
  it instead of a raw float&lt;br /&gt;
- /agedAppleImeis + aged-apple-imeis.vm list the units, excluding activated ones -&lt;br /&gt;
  those are already deducted as activated stock and shown in their own banner, so&lt;br /&gt;
  no handset appears in both&lt;br /&gt;
- click handler added to the existing activated-imeis.js rather than inline in the&lt;br /&gt;
  fragment: an inline script in an AJAX-injected fragment re-registers&lt;br /&gt;
  $(document).on on every load and stacks duplicate requests&lt;br /&gt;
- jsVersion 420 -&gt; 421&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/DashboardController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/InventoryController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/business/activated-imeis.js&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/aged-apple-imeis.vm&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/dashboard-aged-apple-stock.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/dashboard1.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37593&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37593&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 19:19:38 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37592 – Fix live-demo deduction lost in the investment snapshot; maintain aged-Apple ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 8 file(s) modified&lt;/strong&gt;&lt;br/&gt;Fix live-demo deduction lost in the investment snapshot; maintain aged-Apple qty&lt;br /&gt;
&lt;br /&gt;
BUG FIX to r37588. InventoryService.getTotalAmountInStock() returns stock net of&lt;br /&gt;
live-demo units held past 90 days, and both original investment paths assigned&lt;br /&gt;
that netted value to inStockAmount - which is why&lt;br /&gt;
PartnerDailyInvestment.getTotalInvestment() carries no separate demo term. The&lt;br /&gt;
sweep stored the RAW snapshot sum and never applied the deduction, overstating&lt;br /&gt;
investment for 328 partners by Rs 5.19 crore and their limits by roughly Rs 1.3&lt;br /&gt;
crore. Maxwell validated clean earlier only because he holds no demo stock.&lt;br /&gt;
&lt;br /&gt;
Fixed by storing what is measured and deriving what is computed: the column is&lt;br /&gt;
now in_stock_gross_amount and getNetInStockAmount() applies the haircut. The demo&lt;br /&gt;
holding moves on its own daily clock, so storing the netted figure would have&lt;br /&gt;
meant re-netting it in three places every time the haircut changed - the same&lt;br /&gt;
&apos;two things must move together&apos; trap behind the original cache bug. Deriving it&lt;br /&gt;
means a daily demo refresh flows through to stock and base with nothing to sync.&lt;br /&gt;
&lt;br /&gt;
Also:&lt;br /&gt;
- aged_apple_qty stored on the snapshot and maintained on the same daily cycle as&lt;br /&gt;
  aged_apple_stock_amount, so the partner banner reads a saved count instead of&lt;br /&gt;
  running a count query per dashboard load, and count and value can never disagree&lt;br /&gt;
- selectPartnerStockCountMap mirrors selectPartnerStockValueMap, including the&lt;br /&gt;
  activated exclusion&lt;br /&gt;
- selectAgedAppleStock lists the units behind the haircut for the partner view&lt;br /&gt;
- FofoUser exposes aged_apple_stock / aged_apple_qty&lt;br /&gt;
- stock-moved detection compares GROSS: a demo unit crossing 90 days changes net&lt;br /&gt;
  stock but nothing physically moved, and that is the daily refresh&apos;s job&lt;br /&gt;
&lt;br /&gt;
Schema: partner_investment_snapshot.sql updated (in_stock_gross_amount,&lt;br /&gt;
aged_apple_qty). Applied to prod - the table was empty, so it was dropped and&lt;br /&gt;
recreated from the script.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/fofo/PartnerDailyInvestment.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/fofo/PartnerInvestment.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/InventoryItemRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/InventoryItemRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/FofoUser.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/PartnerInvestmentServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/PartnerInvestmentSweepService.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/resources/sql/partner_investment_snapshot.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37592&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37592&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 17:30:13 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37591 – Route V2 admin wallet adjustment through WalletServiceImpl  Byte-identical duplicate ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Route V2 admin wallet adjustment through WalletServiceImpl&lt;br /&gt;
&lt;br /&gt;
Byte-identical duplicate of the fofo /walletUpdate handler, with the same missing&lt;br /&gt;
row lock. Points at the shared walletService.applyManualAdjustment so both&lt;br /&gt;
modules share one code path.&lt;/div&gt;~ /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/V2FofoWalletController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37591&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37591&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 17:30:12 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37590 – Route admin wallet adjustment through WalletServiceImpl  /walletUpdate hand-rolled the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Route admin wallet adjustment through WalletServiceImpl&lt;br /&gt;
&lt;br /&gt;
/walletUpdate hand-rolled the balance update and history row, bypassing the&lt;br /&gt;
service entirely, and read the wallet with selectByRetailerId instead of&lt;br /&gt;
selectByRetailerIdForUpdate - so unlike every other wallet path it took no row&lt;br /&gt;
lock, and a concurrent adjustment and purchase could lose an update.&lt;br /&gt;
&lt;br /&gt;
Now calls walletService.applyManualAdjustment, which reuses getManualReference&lt;br /&gt;
for the reference allocation and routes the movement through&lt;br /&gt;
addAmountToWallet/consumeAmountFromWallet(forced). Behaviour is preserved: admin&lt;br /&gt;
debits stay forced, so they can still push a wallet negative as before. Removes&lt;br /&gt;
~45 duplicated lines.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/WalletController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37590&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37590&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 17:30:03 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37589 – Drive credit limits off the investment sweep; stop phantom limit ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;Drive credit limits off the investment sweep; stop phantom limit writes&lt;br /&gt;
&lt;br /&gt;
Adds the 2-minute sweep schedule and points the limit recalculation at the&lt;br /&gt;
partners whose base_value actually moved, instead of rescanning all 980 every&lt;br /&gt;
20 minutes. Measured on production: 3 partners change per 2-minute window on&lt;br /&gt;
average, peak 18.&lt;br /&gt;
&lt;br /&gt;
- ScheduledSkeleton: 2-min sweepPartnerInvestment, daily refreshAgedStockDaily&lt;br /&gt;
  at 00:20; the 20-min full pass is kept as a backstop for inputs base does not&lt;br /&gt;
  capture (risk, the SIDBI floor, hard_limit)&lt;br /&gt;
- BatchScheduledTasks.sweepPartnerInvestment: sweep, then limits for changed&lt;br /&gt;
  bases only&lt;br /&gt;
- calculateChangedPartnerLimits(restrictTo) to support that&lt;br /&gt;
- scaleMoney(): round to paise before comparing and storing. The limit comes out&lt;br /&gt;
  of a double multiply, so 65123.7400 round-tripped as 65123.740000000005 and&lt;br /&gt;
  compareTo called it a change. 208 of 230 &apos;changed&apos; partners in one production&lt;br /&gt;
  run differed by under half a paisa, rewriting sd_credit_requirement and&lt;br /&gt;
  dtr.credit_account ~14,000 times a day for identical values and churning the&lt;br /&gt;
  SIDBI mirror. Real changes were never below a rupee, so 2dp cannot suppress one.&lt;br /&gt;
- getFirstBillingDates: one grouped query instead of one per partner&lt;br /&gt;
&lt;br /&gt;
Credit limits for 24 partners will rise on the first sweep after deploy - that is&lt;br /&gt;
the aged-Apple double-deduction correction landing (see r37588), not a defect.&lt;br /&gt;
&lt;br /&gt;
NOTE: cron is a standalone Spring Boot jar; the new schedules only fire once it&lt;br /&gt;
is restarted with --spring.profiles.active=scheduled.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/BatchScheduledTasks.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/PartnerLimitHelper.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ScheduledSkeleton.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37589&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37589&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 17:29:49 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37588 – Serve partner investment from a 2-minute snapshot instead of a ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 17 file(s) modified&lt;/strong&gt;&lt;br/&gt;Serve partner investment from a 2-minute snapshot instead of a 3-hour cache&lt;br /&gt;
&lt;br /&gt;
getInvestment() was @Cacheable on a 3-hour Redis cache that addAmountToWallet&lt;br /&gt;
evicted but consumeAmountFromWallet did not. A partner whose advance payment was&lt;br /&gt;
swept straight to a loan had the money counted twice - once as a still-cached&lt;br /&gt;
wallet balance, once as the reduced utilisation - overstating their credit limit&lt;br /&gt;
by the payment x their tier until the cache expired.&lt;br /&gt;
&lt;br /&gt;
Replaced with fofo.partner_investment, refreshed every 2 minutes by&lt;br /&gt;
PartnerInvestmentSweepService. Every coupled term is read in one pass, so wallet&lt;br /&gt;
and utilisation (and in-stock and aged-Apple) can never come from different&lt;br /&gt;
moments. A shorter TTL would only have made the error rarer - it scales with the&lt;br /&gt;
payment, not the delay.&lt;br /&gt;
&lt;br /&gt;
- PartnerInvestment entity/repository + partner_investment_snapshot.sql&lt;br /&gt;
- PartnerInvestmentSweepService: 9 batched reads, stores base_value for change&lt;br /&gt;
  detection, refreshes aged-Apple for partners whose stock moved intra-day&lt;br /&gt;
- getInvestment/getInvestmentsForFofoStores both read the snapshot, so the two&lt;br /&gt;
  paths no longer disagree; live compute retained as fallback&lt;br /&gt;
- selectActivatedStockAmountByFofoIds: batches an N+1 that cost 233ms x 1690&lt;br /&gt;
  partners (6.6 min -&gt; 1.0 s)&lt;br /&gt;
- getFirstBillingDates: batches another N+1 (4.6 s -&gt; 0.67 s)&lt;br /&gt;
- selectPendingGrnOrders(List) now applies the same SD_START_DATE floor as the&lt;br /&gt;
  single-partner overload; the two were reporting different GRN-pending&lt;br /&gt;
- selectPartnerStockValueMap takes excludeActivated: an activated Apple handset&lt;br /&gt;
  held past the aging window was added once to in-stock and subtracted twice&lt;br /&gt;
  (activated stock, then the aged haircut). 90 units, 24 partners, Rs 65.19 lakh&lt;br /&gt;
  double-deducted. Live-demo passes false - no overlap there.&lt;br /&gt;
- applyManualAdjustment: routes the two hand-rolled admin wallet adjustments&lt;br /&gt;
  through WalletServiceImpl so they take the FOR UPDATE lock&lt;br /&gt;
- add_idx_order_grn_pending.sql: covering index, GRN query 1320ms -&gt; 514ms&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/fofo/InventoryItem.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/fofo/PartnerInvestment.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/transaction/Order.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/InventoryItemRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/InventoryItemRepositoryImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/PartnerInvestmentRepository.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/PartnerInvestmentRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/transaction/OrderRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/transaction/TransactionRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/transaction/TransactionRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/inventory/InventoryServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/PartnerInvestmentServiceImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/PartnerInvestmentSweepService.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/wallet/WalletService.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/wallet/WalletServiceImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/add_idx_order_grn_pending.sql&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/partner_investment_snapshot.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37588&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37588&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 15:51:38 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37587 – ticket download option given and some enhancement on notification panel</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;ticket download option given and some enhancement on notification panel&lt;/div&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/model/WarehouseOpeningByMovementModel.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37587&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37587&amp;peg=37604</guid></item>
<item><pubDate>Fri, 11 Sep 2026 15:48:56 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37586 – drr view modification</title><description>&lt;div&gt;&lt;strong&gt;ranu – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;drr view modification&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/RbmTargetService.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/RbmTargetServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/monitors/RbmDrrDashboardController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/rbm-drr-dashboard.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/retailer-details.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37586&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37586&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 17:19:06 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37585 – Fix web-offer sync: selectModelOffers join order (Unknown column &apos;o.id&apos; in ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Fix web-offer sync: selectModelOffers join order (Unknown column &apos;o.id&apos; in &apos;on clause&apos;)&lt;br /&gt;
&lt;br /&gt;
selectModelOffers led its FROM with offers.offer_product p and then joined&lt;br /&gt;
offers.offer_raw_row r ON r.offer_id = o.id, referencing alias o one join&lt;br /&gt;
before o was introduced. An ON clause resolves only against tables already&lt;br /&gt;
in the join order, so MySQL rejected it with SQLSyntaxErrorException:&lt;br /&gt;
Unknown column &apos;o.id&apos; in &apos;on clause&apos;. Every per-model sync since r37581 has&lt;br /&gt;
therefore failed - webOfferSync=FAILED on the 15:04 and 17:14 re-ingests of&lt;br /&gt;
document 4 - leaving the 166 legacy NULL-key row-badges active and zero&lt;br /&gt;
consolidated badges published.&lt;br /&gt;
&lt;br /&gt;
Reordered to lead with offers.offer o, matching the proven shape of the&lt;br /&gt;
sibling selectRowOffers query. All three are inner joins so the result set&lt;br /&gt;
is unchanged; BEST_OFFER_WINS and ORDER BY p.catalog_id still resolve.&lt;br /&gt;
&lt;br /&gt;
Verified by executing the corrected statement read-only against prod for&lt;br /&gt;
document 4: 733 rows over 314 distinct catalog ids, the expected model&lt;br /&gt;
count. Not caught by tests because all 53 offercircular tests are&lt;br /&gt;
stub-based (no Spring, no DB) and never execute this SQL.&lt;br /&gt;
&lt;br /&gt;
Failure was visible only because r37568 records webOfferSync= in&lt;br /&gt;
ingest_summary; the runner still swallows the exception by design.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37585&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37585&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 15:24:07 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37584 – ticket download option given and some enhancement on notification panel</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;ticket download option given and some enhancement on notification panel&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/rbm-drr-dashboard.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37584&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37584&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 15:21:19 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37583 – ticket download option given and some enhancement on notification panel</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;ticket download option given and some enhancement on notification panel&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/rbm-drr-dashboard.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37583&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37583&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 15:13:31 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37582 – ticket download option given and some enhancement on notification panel</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;ticket download option given and some enhancement on notification panel&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/rbm-drr-dashboard.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37582&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37582&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 14:58:44 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37581 – web offer sync: retire the pre-consolidation badges instead of deleting ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer sync: retire the pre-consolidation badges instead of deleting them&lt;br /&gt;
&lt;br /&gt;
The sync now deactivates any CIRCULAR row with a NULL circular_offer_key on its next&lt;br /&gt;
run. A row-keyed badge is a fragment of what a consolidated badge says, so leaving it&lt;br /&gt;
active would show a partner the same offer twice - once whole and once in pieces.&lt;br /&gt;
&lt;br /&gt;
That removes the DELETE from the migration entirely, which is strictly better:&lt;br /&gt;
&lt;br /&gt;
  * nothing is destroyed, so a bad sync is one UPDATE away from being undone&lt;br /&gt;
  * web_offer_product has NO foreign key to web_offer, so the DELETE had to clear its&lt;br /&gt;
    532 rows separately or strand them as orphans&lt;br /&gt;
  * no window where a circular has no badges at all - the old ones stay live until the&lt;br /&gt;
    new ones exist&lt;br /&gt;
&lt;br /&gt;
The migration is now purely additive: one ALTER, safe to run ahead of the deploy, which&lt;br /&gt;
is how it was applied to prod.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/resources/sql/add_web_offer_per_model.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37581&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37581&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 14:55:17 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37580 – web offer: state an EMI scheme the circular gave without ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer: state an EMI scheme the circular gave without months&lt;br /&gt;
&lt;br /&gt;
  Rs.2,500 on Credit Card EMI (CIB) with IDFC First Bank, Kotak Mahindra Bank&lt;br /&gt;
&lt;br /&gt;
52 Sep&apos;26 offers have a bare &apos;CIB&apos; tenure cell - the circular names the EMI type and&lt;br /&gt;
gives no months. TenureParser correctly yields no tenure row for a cell with no digits,&lt;br /&gt;
so the type vanished and the badge said only &apos;on Credit Card EMI&apos;. Every one of those&lt;br /&gt;
52 carries a cashback, so it was 52 offers&apos; worth of SKUs silent about the EMI they&lt;br /&gt;
apply to.&lt;br /&gt;
&lt;br /&gt;
The type is stated because the circular stated it. The MONTHS are not invented,&lt;br /&gt;
because it did not give them - the same line the CIB expansion was left on.&lt;br /&gt;
&lt;br /&gt;
Read from offer_raw_row.col_emi_tenure rather than stored: &apos;scheme, no month&apos; is not a&lt;br /&gt;
tenure, and offer_tenure.tenure_months is NOT NULL, so persisting it would mean a fake&lt;br /&gt;
0 row standing for a fact that is not a tenure.&lt;br /&gt;
&lt;br /&gt;
Only ever attached to an EMI mode, and real tenures always win over the bare code.&lt;br /&gt;
&lt;br /&gt;
ModelOfferTest 8 -&gt; 11.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/WebOfferSyncService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/ModelOfferTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37580&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37580&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 13:47:02 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37579 – web offer: one badge per model, consolidating everything the circular ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer: one badge per model, consolidating everything the circular grants it&lt;br /&gt;
&lt;br /&gt;
Edge 60 Pro 12+256 carried five badges - a Full Swipe cashback, an EMI cashback and&lt;br /&gt;
three EMI schemes - and the partner&apos;s card listed all five. It now carries one:&lt;br /&gt;
&lt;br /&gt;
  SEPTEMBER 2026 Motorola Cashback Offer-2,500 On Credit Card EMI&lt;br /&gt;
                                         &amp; 2,000 On Credit Card Full Swipe&lt;br /&gt;
&lt;br /&gt;
Models whose consolidated terms are IDENTICAL share a badge, so 314 models collapse to&lt;br /&gt;
~107 rows while every model still appears in exactly one.&lt;br /&gt;
&lt;br /&gt;
Rules, from the taxonomy: any model has cashback on Full Swipe and/or EMI, instant or&lt;br /&gt;
deferred, plus NCE/LCE/CIB with tenures, and any of it may differ per bank.&lt;br /&gt;
- &apos;Upto&apos; only where a mode carries several values - which is what per-bank pricing&lt;br /&gt;
  looks like. One value is stated plainly.&lt;br /&gt;
- Highest value first.&lt;br /&gt;
- Banks ride with each line only when they DIFFER; one shared set is hoisted to a&lt;br /&gt;
  single trailing &apos;Banks:&apos; line. A third of models need the per-line form.&lt;br /&gt;
- An amount whose window is narrower than the badge&apos;s states its own end date. Apple&lt;br /&gt;
  1025780 pays Rs.6,000 to the 16th then Rs.4,000 to the 26th; without this the badge&lt;br /&gt;
  would advertise Rs.6,000 for ten days it is not available.&lt;br /&gt;
&lt;br /&gt;
⚠️ Banks and tenures belong to the OFFER a line came from, never to the model. On Edge&lt;br /&gt;
60 Pro the no-cost EMI is ICICI on 3 and 6 months but SBI on 3 only, and the EMI&lt;br /&gt;
cashback is IDFC/Kotak with no tenure at all. Attaching the model&apos;s tenures to its&lt;br /&gt;
cashback would promise no-cost EMI on a bank that never offered it. This also corrects&lt;br /&gt;
an earlier reading of mine that called the SBI 3-month line a duplicate of ICICI&apos;s -&lt;br /&gt;
it is a different bank, not noise.&lt;br /&gt;
&lt;br /&gt;
New ModelOfferTest, 8 cases, every one taken from a real Sep&apos;26 row.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/WebOfferSyncService.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/ModelOfferTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37579&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37579&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 13:46:45 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37578 – web offer sync: read what the circular grants each MODEL, ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer sync: read what the circular grants each MODEL, not each row&lt;br /&gt;
&lt;br /&gt;
selectModelOffers returns one row per (catalog_id, benefit), carrying the context that&lt;br /&gt;
qualifies it - the banks it applies to, its tenures and their scheme, the timing and&lt;br /&gt;
the window. Consolidation happens in the service; this is the read it needs.&lt;br /&gt;
&lt;br /&gt;
LEFT JOIN on the benefit, because a scheme-only offer carries no cashback and dropping&lt;br /&gt;
it here would lose the NCE/LCE badge entirely.&lt;br /&gt;
&lt;br /&gt;
Content-keyed writes alongside: selectSyncedByKey, insertKeyedWebOffer,&lt;br /&gt;
replaceProducts, deactivateMissingKeys. A badge is now identified by a sha256 of its&lt;br /&gt;
terms, so models with identical terms share one and a model appears in exactly one.&lt;br /&gt;
&lt;br /&gt;
Migration add_web_offer_per_model.sql adds circular_offer_key + its unique key, and&lt;br /&gt;
drops the row-keyed CIRCULAR badges - one of those is a fragment of what a&lt;br /&gt;
content-keyed badge says and there is no mapping from five fragments to one whole, so&lt;br /&gt;
they are regenerated by the next ingest.&lt;br /&gt;
&lt;br /&gt;
⚠️ web_offer_product has NO foreign key to web_offer, so its rows do not cascade and&lt;br /&gt;
are deleted explicitly or they are orphaned. web_offer_sync_shadow does cascade.&lt;br /&gt;
source=&apos;CIRCULAR&apos; only - the 3,850 hand-authored rows are never touched.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/add_web_offer_per_model.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37578&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37578&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 13:17:50 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37577 – web offer: an EMI cashback names its tenures WITH their ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer: an EMI cashback names its tenures WITH their scheme&lt;br /&gt;
&lt;br /&gt;
  Rs.2,500 on Credit Card EMI (NCE 3, 6; LCE 9, 12 months)&lt;br /&gt;
&lt;br /&gt;
A bare &apos;3, 6, 9, 12 months&apos; says which tenures earn the cashback but not which of&lt;br /&gt;
them are no-cost - and at the counter the two facts are only useful together.&lt;br /&gt;
&lt;br /&gt;
The trailing scheme sentence is dropped when an EMI benefit already carried it, since&lt;br /&gt;
it would state the same thing twice. It stays when the cashback is on Full Swipe only:&lt;br /&gt;
EMI is still available, it just is not what the cashback is on.&lt;br /&gt;
&lt;br /&gt;
Tenures whose scheme the circular never gave keep their months but carry no label -&lt;br /&gt;
the months are real, the scheme would be invented.&lt;br /&gt;
&lt;br /&gt;
Tests 16 -&gt; 18.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/WebOfferSyncService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/WebOfferSyncServiceTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37577&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37577&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 13:02:55 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37576 – ticket download option given and some enhancement on notification panel</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;ticket download option given and some enhancement on notification panel&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/rbm-drr-dashboard.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37576&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37576&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 12:51:28 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37575 – ticket download option given and some enhancement on notification panel</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;ticket download option given and some enhancement on notification panel&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/rbm-drr-dashboard.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37575&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37575&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 12:45:42 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37574 – web offer: print the EMI scheme code, not a guessed ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer: print the EMI scheme code, not a guessed expansion&lt;br /&gt;
&lt;br /&gt;
NCE / LCE / CIB are industry standard and now appear verbatim:&lt;br /&gt;
&lt;br /&gt;
  Instant cashback. Rs.3,000 on Credit Card EMI (3, 6 months);&lt;br /&gt;
  Rs.3,000 on Credit Card Full Swipe. LCE on 3, 6 months. Banks: ...&lt;br /&gt;
&lt;br /&gt;
The expansions were not ours to invent. emi_scheme.display_name carries &apos;Cashback&lt;br /&gt;
Instant Benefit&apos; for CIB, and the evidence contradicts it: the Sep&apos;26 cell&lt;br /&gt;
&apos;3 NC 6,9,12 CIB&apos; puts CIB in ONE ladder with NCE, so it describes who bears the&lt;br /&gt;
interest on a tenure rather than how a cashback is delivered - and 53 of 55 CIB rows&lt;br /&gt;
carry a separate cashback amount anyway, which that expansion would make redundant.&lt;br /&gt;
Pine Labs&apos; own docs define ICB as Instant Cashback on UPI; the circular writes CIB 60&lt;br /&gt;
times and ICB never.&lt;br /&gt;
&lt;br /&gt;
A guessed expansion on a partner badge risks stating the opposite of the truth - for&lt;br /&gt;
CIB, advertising a benefit where the customer may in fact be bearing the interest.&lt;br /&gt;
The code cannot be wrong that way.&lt;br /&gt;
&lt;br /&gt;
A scheme is still stated ONLY when the circular gave one; tenures with no scheme are&lt;br /&gt;
described as nothing at all.&lt;br /&gt;
&lt;br /&gt;
Also fixes the singular: &apos;NCE on 3 month&apos;, not &apos;3 months&apos;.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/WebOfferSyncService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/WebOfferSyncServiceTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37574&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37574&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 12:45:13 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37573 – ui look and feel color changing mode for drr</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;ui look and feel color changing mode for drr&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/rbm-drr-dashboard.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37573&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37573&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 12:34:31 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37572 – web offer: state the whole offer in the title, and ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer: state the whole offer in the title, and the EMI scheme in the detail&lt;br /&gt;
&lt;br /&gt;
Title now states EVERY payment mode, highest first, in the house style of the&lt;br /&gt;
hand-written rows:&lt;br /&gt;
&lt;br /&gt;
  SEPTEMBER 2026 Samsung Cashback Offer-3000 On Credit Card Full Swipe&lt;br /&gt;
                                        &amp; 3000 On Credit Card EMI &amp; 3000 On UPI&lt;br /&gt;
&lt;br /&gt;
A partner scanning the card should see the whole offer, not just its best number.&lt;br /&gt;
Brand keeps its catalog casing (Samsung, not SAMSUNG). A scheme-only offer is still&lt;br /&gt;
titled by its scheme - calling it a cashback offer is what produced the live&lt;br /&gt;
&apos;Cashback Offer- NA&apos; badges.&lt;br /&gt;
&lt;br /&gt;
Detail additions:&lt;br /&gt;
- the EMI scheme, when the circular gave one: &apos;... Low Cost EMI on 3, 6 months.&apos;&lt;br /&gt;
  The circular states it in its own column (&apos;3m,6m LCE&apos; beside &apos;3000 CC Full&lt;br /&gt;
  Swipe/CC EMI/UPI&apos;) and a partner needs both halves.&lt;br /&gt;
- eligible tenures on an EMI benefit: &apos;Rs.3,000 on Credit Card EMI (3, 6 months)&apos;.&lt;br /&gt;
  Cashback &apos;on Credit Card EMI&apos; is not actionable without knowing which tenures&lt;br /&gt;
  qualify. Full Swipe and UPI carry no tenure, so they get none.&lt;br /&gt;
&lt;br /&gt;
⚠️ A scheme is stated ONLY when the circular gave one. Tenures with no scheme are&lt;br /&gt;
described as nothing at all - naming them would read as a no-cost or low-cost claim&lt;br /&gt;
that was never made.&lt;br /&gt;
&lt;br /&gt;
Tests 14 -&gt; 16.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/WebOfferSyncService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/WebOfferSyncServiceTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37572&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37572&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 12:34:19 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37571 – offer circular: the month unit was swallowing the EMI scheme ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;offer circular: the month unit was swallowing the EMI scheme marker&lt;br /&gt;
&lt;br /&gt;
&apos;M&apos; is the month UNIT, not a separator, but the token loop flushed on it. &apos;3m,6m LCE&apos;&lt;br /&gt;
tokenises to 3, M, 6, M, LCE - each M banked its month as NONE, so the LCE arrived&lt;br /&gt;
with nothing pending and was silently lost.&lt;br /&gt;
&lt;br /&gt;
74 Sep&apos;26 offers carry a scheme in the tenure cell that never reached offer_tenure;&lt;br /&gt;
22 of them through this path (&apos;3m,6m LCE&apos;, &apos;6m,9m LCE&apos;, &apos;3m &amp; 6m LCE&apos;, &apos;3m, 6m, 9m,&lt;br /&gt;
12m, 18m, 24m LCE&apos;). The rest are bare &apos;CIB&apos; cells with no months at all, which is a&lt;br /&gt;
separate case and left alone.&lt;br /&gt;
&lt;br /&gt;
It also fixes &apos;3M (NCE), 6M &amp; Above LCE&apos;, where the M flushed BOTH groups before&lt;br /&gt;
either marker was seen - so an offer that is no-cost on 3 months and low-cost beyond&lt;br /&gt;
recorded neither.&lt;br /&gt;
&lt;br /&gt;
This is money: no-cost EMI costs the customer nothing and low-cost does not, so a lost&lt;br /&gt;
marker is a term a partner could quote wrongly at the counter.&lt;br /&gt;
&lt;br /&gt;
Months with no marker anywhere still bank as NONE via the end-of-cell flush - the same&lt;br /&gt;
answer the M branch used to give for a genuinely unmarked cell.&lt;br /&gt;
&lt;br /&gt;
New TenureParserTest, 6 cases, covering the regression and the shapes that must not&lt;br /&gt;
change.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/TenureParser.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/TenureParserTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37571&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37571&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 12:31:14 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37570 – drr view color change</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;drr view color change&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/rbm-drr-dashboard.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37570&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37570&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 12:05:44 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37569 – fcm: stop holding a row lock on the whole batch ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;fcm: stop holding a row lock on the whole batch across every FCM call&lt;br /&gt;
&lt;br /&gt;
sendNotification lived in ScheduledTasks, which carries a class-level @Transactional,&lt;br /&gt;
so one pass was one transaction: it loaded EVERY pending row uncapped, then per row&lt;br /&gt;
made an FCM call over the network and stamped sentTimestamp on the entity. A dirty&lt;br /&gt;
row stays write-locked until commit, so a run held a lock on every notification in&lt;br /&gt;
the batch for the SUM of all the remote waits. Volume is real -- 11,581 sent on&lt;br /&gt;
2026-09-09, 12,036 on 2026-09-05 -- and HttpClientFactory sets a 10s socket timeout,&lt;br /&gt;
so one bad run could hold thousands of locks for minutes.&lt;br /&gt;
&lt;br /&gt;
That is the shape behind a 33 SECOND average InnoDB row-lock wait server-wide&lt;br /&gt;
(Innodb_row_lock_time 63,291s over 15.4 days uptime, max 51,941ms against a 50s&lt;br /&gt;
innodb_lock_wait_timeout -- which is where LockAcquisitionException comes from).&lt;br /&gt;
&lt;br /&gt;
Moved to PushNotificationSendService using the same seam the invoicing pass already&lt;br /&gt;
uses in InvoiceService.updateIrnsToInvoices: one short read transaction to pick up&lt;br /&gt;
the batch and build the payloads, NO transaction across the network call, and one&lt;br /&gt;
REQUIRES_NEW transaction per row to record the outcome. No lock is held while waiting&lt;br /&gt;
on FCM.&lt;br /&gt;
&lt;br /&gt;
It is a separate bean, and reaches its own transactional methods through an injected&lt;br /&gt;
self-reference, because REQUIRES_NEW is applied by a Spring proxy and a plain&lt;br /&gt;
self-invocation would bypass it -- same idiom, for the same reason, as InvoiceService.&lt;br /&gt;
&lt;br /&gt;
Also caps the batch at 500/run (30,000/hour against a 12,000 peak day) using the&lt;br /&gt;
already-present but never-wired selectPendingNotifications(limit); the previous query&lt;br /&gt;
was uncapped, which is what let a campaign burst become one multi-minute transaction.&lt;br /&gt;
Send outcomes are unchanged: 200 stamps now, anything else stamps the 1970 sentinel.&lt;br /&gt;
The HttpClient is now closed, which it previously was not.&lt;/div&gt;+ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/PushNotificationSendService.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ScheduledTasks.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37569&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37569&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 12:04:40 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37568 – offer circular: a failed web-offer sync must not be silent ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;offer circular: a failed web-offer sync must not be silent&lt;br /&gt;
&lt;br /&gt;
Swallowing the exception was right - a circular that parsed correctly must stay&lt;br /&gt;
PUBLISHED, and the sync is re-runnable while the parse is the expensive part.&lt;br /&gt;
Swallowing it SILENTLY was not.&lt;br /&gt;
&lt;br /&gt;
A TINYINT(1) cast threw in the sync on every ingest from 2026-09-08 to r37553 and&lt;br /&gt;
nothing looked wrong: processed_at advanced, the circular published, the email said&lt;br /&gt;
success. The only symptom was web_offer.synced_at standing still, which nobody was&lt;br /&gt;
watching. It went unnoticed for two days.&lt;br /&gt;
&lt;br /&gt;
Now:&lt;br /&gt;
- Summary carries webOfferSync, and states it in EVERY case - the counts on success,&lt;br /&gt;
  &apos;FAILED - &amp;lt;cause&gt;&apos; on failure, &apos;NOT RUN&apos; if it never executed. A missing line would&lt;br /&gt;
  be indistinguishable from a sync that never ran, so there is no missing line.&lt;br /&gt;
- That lands in offer_document.ingest_summary, so the review screen shows it.&lt;br /&gt;
- The notification email carries it too, and a failure renders as a red&lt;br /&gt;
  &apos;Web offers NOT updated&apos; block saying partners are still seeing the previous&lt;br /&gt;
  offers and that the parse itself is fine.&lt;br /&gt;
- The sync now runs BEFORE published(), so its outcome is part of what gets recorded&lt;br /&gt;
  rather than an afterthought. It is still REQUIRES_NEW with its exception caught, so&lt;br /&gt;
  it still cannot fail the ingest.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CircularIngestRunner.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CircularIngestService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37568&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37568&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 11:58:19 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37567 – Schedule the catalogue delist daily at 05:30  Runs 30 ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Schedule the catalogue delist daily at 05:30&lt;br /&gt;
&lt;br /&gt;
Runs 30 minutes before the existing 06:00 scheduledPushDataToSolr in the same&lt;br /&gt;
class, so the same morning&apos;s reindex publishes it. A bulk UPDATE fires no&lt;br /&gt;
TagListingChangeListener event, so without that ordering the portal would lag&lt;br /&gt;
until 18:00.&lt;br /&gt;
&lt;br /&gt;
Gated on catalog.autoDelist.enabled with an inline default of true - env profiles&lt;br /&gt;
have no fallback between each other, so a key missing from one profile&apos;s&lt;br /&gt;
properties would otherwise stop the context booting.&lt;br /&gt;
&lt;br /&gt;
Also exposes --delistDeadListings for a manual run, honouring the same flag.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/Application.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/b2b/Listing.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37567&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37567&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 11:58:08 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37566 – Delist logic v3: require a month of no movement; add ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;Delist logic v3: require a month of no movement; add CatalogDelistService&lt;br /&gt;
&lt;br /&gt;
Zero stock alone was too weak a test. It fired on SKUs partners were still&lt;br /&gt;
transacting, where the recent movement was often the very sale that emptied the&lt;br /&gt;
stock. v3 additionally requires no movement for a month on either side:&lt;br /&gt;
- SmartDukaan via warehouse.scanNew (3.4M rows, live). Note warehouse.scan is a&lt;br /&gt;
  dead Saholic relic - 2,476 rows, last write 2012.&lt;br /&gt;
- any partner via fofo.scan_record, any scan type.&lt;br /&gt;
Phrased as NOT EXISTS so they short-circuit on the first recent row and use the&lt;br /&gt;
(inventoryItemId, scannedAt) / (inventory_item_id, create_timestamp) indexes.&lt;br /&gt;
An item that has never moved still qualifies, which is correct.&lt;br /&gt;
&lt;br /&gt;
Also in v3:&lt;br /&gt;
- the internal pseudo-brands (Dummy, FOC, FOC HANDSET, Live Demo) are no longer&lt;br /&gt;
  excluded and are swept like anything else.&lt;br /&gt;
- vendor-PO guard narrowed to status = 1. PARTIALLY_FULFILLED is UNREACHABLE,&lt;br /&gt;
  not merely rare: none of the 8 PO-status writes in the codebase sets it, no&lt;br /&gt;
  native SQL writes the column, and status = 2 has 0 rows across 51,593+ POs&lt;br /&gt;
  back to 2011. Partial receipt is modelled per line (unfulfilledQuantity), so a&lt;br /&gt;
  part-received PO sits in READY and is already caught. Documented so it is not&lt;br /&gt;
  &apos;restored&apos; later as a supposed gap.&lt;br /&gt;
&lt;br /&gt;
CatalogDelistService/Impl mirrors the migration statement for statement, for the&lt;br /&gt;
daily scheduled run. Bulk SQL rather than per-row updateActiveById +&lt;br /&gt;
publishStatusChange, which would commit to Solr once per catalog (~1,750 times&lt;br /&gt;
on the 2026-09-10 backlog); the job is instead scheduled ahead of the existing&lt;br /&gt;
06:00 full reindex. The dark-model step is deliberately house-wide rather than&lt;br /&gt;
run-scoped so it converges instead of leaving pre-existing dark models on a&lt;br /&gt;
stale RUNNING forever.&lt;br /&gt;
&lt;br /&gt;
rollback_delist_recent_movement_20260910.sql restores the 24 listings / 21&lt;br /&gt;
models that the v2 run delisted before NEW 3 existed; their partners had&lt;br /&gt;
transacted them within the month. Id list frozen, not re-derived.&lt;/div&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/catalog/CatalogDelistService.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/catalog/CatalogDelistServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/resources/sql/delist_inactive_listings_rolling_24m.sql&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/rollback_delist_recent_movement_20260910.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37566&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37566&amp;peg=37604</guid></item>
<item><pubDate>Thu, 10 Sep 2026 03:00:55 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37565 – IMEI activation: 20s tick lanes for oppo/realme/vivo, idle once the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 7 file(s) modified&lt;/strong&gt;&lt;br/&gt;IMEI activation: 20s tick lanes for oppo/realme/vivo, idle once the day clears&lt;br /&gt;
&lt;br /&gt;
Replaces the two once-a-day passes with chunk-per-tick lanes. Each tick takes one&lt;br /&gt;
chunk and returns; when a brand&apos;s pool comes back empty its turn is skipped, and&lt;br /&gt;
when everything is clear the ticks do nothing and stay silent until midnight.&lt;br /&gt;
&lt;br /&gt;
- browser lane (StandAlone): one chunk of 25 for one brand every 20s, oppo and&lt;br /&gt;
  realme by turns. Still exactly one ChromeDriver alive at a time.&lt;br /&gt;
- vivo lane: its own tick, chunk of 250. It must not share the browser lane --&lt;br /&gt;
  0.24s an imei against oppo&apos;s 10.2s means it would need ~70 hours behind them&lt;br /&gt;
  for work it does alone in 39 minutes.&lt;br /&gt;
&lt;br /&gt;
The snapshot is gone; the pool query is the cursor. That is what makes a restart&lt;br /&gt;
cost one chunk instead of the day: the 12:03 restart on 09-Sep forfeited ~4,000&lt;br /&gt;
lookups and the whole afternoon, and last_finish had read -1 for three days.&lt;br /&gt;
&lt;br /&gt;
The snapshot existed to stop the re-ask loop (realme, 29-Aug: 4,524 requests&lt;br /&gt;
against 1,004 distinct imeis). That is now closed at the source instead -- oppo,&lt;br /&gt;
realme and motorola stamp every imei they asked about, not just the ones that&lt;br /&gt;
produced a map entry, so a failed lookup rests until tomorrow rather than coming&lt;br /&gt;
back on the next tick. Motorola is fixed pre-emptively; nothing schedules it yet.&lt;br /&gt;
&lt;br /&gt;
Also:&lt;br /&gt;
- secondary and tertiary are merged by turns rather than concatenated. Safe while&lt;br /&gt;
  a pass walked to the end; without that guarantee oppo&apos;s 163 tertiary serials sat&lt;br /&gt;
  behind 3,819 secondary ones and would only be reached on a day that cleared.&lt;br /&gt;
- vivo abandons a tick rather than the chunk when the captcha solver returns no&lt;br /&gt;
  code -- one probe per 20s while it is down instead of 250, and no rows rested&lt;br /&gt;
  over a transient outage.&lt;br /&gt;
- the funnel gauges move from a pass to a day. due is measured on the first tick&lt;br /&gt;
  after midnight, the rest accumulate, and last_finish_epoch becomes a real&lt;br /&gt;
  completion clock. Truncation is detected at the midnight rollover, which is the&lt;br /&gt;
  case that never reaches an end-of-run at all.&lt;br /&gt;
&lt;br /&gt;
This does not create capacity. At the 21s/imei measured on 09-Sep the pool still&lt;br /&gt;
needs ~35 hours and will not clear; it now rolls over visibly instead of silently.&lt;br /&gt;
The lever for that is DAYS=1.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/monitored/ImeiActivationGauges.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/MotorolaImeiActivationService.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/OppoImeiActivationService.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/RealmeImeiActivationService.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ScheduledSkeleton.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/StandAlone.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/VivoImeiActivationService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37565&amp;peg=37604</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37565&amp;peg=37604</guid></item>
</channel></rss>