<?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>Thu, 08 Oct 2026 13:05:53 +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=37708</link><atom:link href="https://svn.smartdukaan.com/rss.php?peg=37708&amp;repname=SmartDukaan" rel="self" type="application/rss+xml" />
<item><pubDate>Fri, 18 Sep 2026 04:26:13 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37708 – Migration: state the algorithm and lock mode, and why it ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Migration: state the algorithm and lock mode, and why it runs before the release&lt;br /&gt;
&lt;br /&gt;
hadb1 is MySQL 5.7, so adding a column rebuilds the table rather than only touching metadata.&lt;br /&gt;
At ~53k rows that is seconds and InnoDB permits concurrent reads and writes throughout, but&lt;br /&gt;
ALGORITHM/LOCK are now stated explicitly so it fails loudly rather than quietly taking a table&lt;br /&gt;
lock if that ever stops holding.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/resources/sql/add_po_reopened_at_20260918.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37708&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37708&amp;peg=37708</guid></item>
<item><pubDate>Fri, 18 Sep 2026 04:21:02 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37707 – GRN price mismatch: say which PO the invoice will be ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;GRN price mismatch: say which PO the invoice will be received against, and what to do if it closes first&lt;br /&gt;
&lt;br /&gt;
Resolving a price mismatch discards the PO line and raises a replacement dated to the invoice. That&lt;br /&gt;
replacement is what the invoice is received against, so it is the one that has to stay open long&lt;br /&gt;
enough for the stock to arrive - and it closes on its own after four days for a movement, six for a&lt;br /&gt;
vendor order. Until now nothing said so: the GRN simply stopped matching and the correction sat&lt;br /&gt;
holding stock that had already arrived.&lt;br /&gt;
&lt;br /&gt;
The confirmation now states what is about to happen and what to do if the stock lands late, and the&lt;br /&gt;
request screen explains what Po Id is. Reopening is offered only where it exists - a movement can be&lt;br /&gt;
reopened from Purchase Orders, a vendor order cannot and needs a fresh PO.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/warehouse-purchase.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/warehouse-grn-request-items.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37707&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37707&amp;peg=37708</guid></item>
<item><pubDate>Fri, 18 Sep 2026 04:20:00 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37706 – cart: take the cart row before any line, to break ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;cart: take the cart row before any line, to break a lock-ordering deadlock&lt;br /&gt;
&lt;br /&gt;
InnoDB was rolling back cart edits with &quot;Deadlock found when trying to get lock&quot;&lt;br /&gt;
(GlitchTip #53, 27 deadlocks) and losing others to OptimisticLockException&lt;br /&gt;
&quot;actual row count: 0; expected: 1&quot; (11 issues, 42 events). Both are the same cause.&lt;br /&gt;
&lt;br /&gt;
Two request paths took the same two rows in OPPOSITE orders. Adding a line INSERTs&lt;br /&gt;
into user.line, and line_cart_id_fk shared-locks the parent cart FIRST, line second.&lt;br /&gt;
Validation/hydration mutated the line rows FIRST and wrote cart.total_price second.&lt;br /&gt;
Run those concurrently on one cart and it is a cycle. Caught in the act on prod:&lt;br /&gt;
&lt;br /&gt;
  T1: INSERT user.line (cart_id=175180781)  -&gt; holds S on cart, waits S on line&lt;br /&gt;
  T2: UPDATE user.cart SET total_price=269340.0, version=175 WHERE version=174&lt;br /&gt;
                                            -&gt; holds X on line, waits X on cart&lt;br /&gt;
  *** WE ROLL BACK TRANSACTION (1)&lt;br /&gt;
&lt;br /&gt;
Fix is to give every mutating path one order: cart, then lines. CartRepository gains&lt;br /&gt;
selectByIdForUpdate, and it is called as the first statement of each path that writes&lt;br /&gt;
a cart line. Re-taking it inside one request is a no-op.&lt;br /&gt;
&lt;br /&gt;
A lock-ordering fix is all-or-nothing -- one path in the wrong order is enough to&lt;br /&gt;
re-form the cycle -- so this covers ALL TEN cart-line writers, not just the two that&lt;br /&gt;
happened to show up in the stack traces: createCartItem, clearCart, getCartValidation,&lt;br /&gt;
addItemsToCart (x2), addShoppingBag, validateForOpen (x2) and V2BillingController&apos;s&lt;br /&gt;
bind/unbindInsurance. The audit is worth re-running before adding another writer.&lt;br /&gt;
&lt;br /&gt;
Note validateForOpen and getCartValidation WRITE despite their names (they correct&lt;br /&gt;
cart_line quantity/price and roll up cart.total_price), which is why a &quot;validate&quot; call&lt;br /&gt;
was ever holding write locks. The lock is placed accordingly; making those genuinely&lt;br /&gt;
read-only is a separate, larger change.&lt;br /&gt;
&lt;br /&gt;
This also serialises concurrent edits to the SAME cart, which is what the @Version&lt;br /&gt;
column on Cart was already trying and failing to express. Different carts are&lt;br /&gt;
different rows, so there is no cost across partners.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/cart/CartServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/cart/v2/CartValidationServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/user/CartRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/user/CartRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/V2BillingController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37706&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37706&amp;peg=37708</guid></item>
<item><pubDate>Fri, 18 Sep 2026 04:19:28 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37705 – PO list: show the transaction id so a movement can ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;PO list: show the transaction id so a movement can be found from the invoice being received&lt;br /&gt;
&lt;br /&gt;
An internal movement is raised as a transaction, so the invoice on the GRN desk leads straight back to its PO&lt;br /&gt;
through that id. The list is a DataTable, so having the column makes it searchable - which is how someone finds&lt;br /&gt;
the PO to reopen when a receipt arrives after auto-close, instead of hunting through date ranges.&lt;br /&gt;
&lt;br /&gt;
Placed after Status so existing column positions are unchanged.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/warehouse-purchase-order.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37705&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37705&amp;peg=37708</guid></item>
<item><pubDate>Fri, 18 Sep 2026 04:18:12 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37704 – Reopen a movement PO whose stock arrived late, and stop ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 8 file(s) modified&lt;/strong&gt;&lt;br/&gt;Reopen a movement PO whose stock arrived late, and stop stranding GRN price corrections&lt;br /&gt;
&lt;br /&gt;
Internal movements auto-close after four days, which fits 99.6% of them - 5,491 of 5,515 receipts&lt;br /&gt;
land inside the window. The remainder leave the PO closed with the stock still in transit and&lt;br /&gt;
nowhere to receive it: 998 internal POs closed during 2026 still holding 21,996 unreceived units.&lt;br /&gt;
&lt;br /&gt;
A closed movement PO can now be reopened from the purchase order list. Reopening stamps&lt;br /&gt;
reopenedAt, and auto-close measures from WarehousePurchaseOrder.getOpenSince() - reopenedAt when&lt;br /&gt;
set, the PO date otherwise - so a reopened PO gets the same fresh window a new one gets instead of&lt;br /&gt;
being closed straight back on the next sweep. Only movements between our own warehouses: an&lt;br /&gt;
external vendor PO that has closed is settled with that vendor, not reopened unilaterally.&lt;br /&gt;
&lt;br /&gt;
Separately, a GRN price correction now checks that the PO it just raised is one the invoice can&lt;br /&gt;
actually be received against. Matching reads POs that are open and approved for the same supplier&lt;br /&gt;
and warehouse dated on or before the invoice; it never looks at the PO being corrected, so what&lt;br /&gt;
matters is that the new PO is receivable. 54 were not - backdated into INIT by the old approval&lt;br /&gt;
gate, hence outside the match - and each stranded silently: original line discarded, GRN completed&lt;br /&gt;
without it, the correction left holding a reservation for stock that had already arrived.&lt;br /&gt;
&lt;br /&gt;
isOpen() names the open set - INIT, READY, PARTIALLY_FULFILLED - that the movement and commitment&lt;br /&gt;
queries already read.&lt;br /&gt;
&lt;br /&gt;
Migration sql/add_po_reopened_at_20260918.sql adds reopenedAt, nullable and additive. It must run&lt;br /&gt;
before this ships: the entity maps the column.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/purchaseorder/POScheduler.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/warehouse/WarehousePurchaseOrder.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/resources/sql/add_po_reopened_at_20260918.sql&lt;br /&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/warehouse/PurchaseOrderController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/warehouse-purchase.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/warehouse-purchase-order.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37704&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37704&amp;peg=37708</guid></item>
<item><pubDate>Fri, 18 Sep 2026 04:10:51 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37703 – GRN price mismatch: ask for the original PO to be ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;GRN price mismatch: ask for the original PO to be reopened instead of stranding a correction PO&lt;br /&gt;
&lt;br /&gt;
Resolving a price mismatch raised a correction PO dated to the supplier invoice, and stored its id&lt;br /&gt;
on the GRN request item to receive against. But by then the stock has already arrived and the PO it&lt;br /&gt;
corrects is closed - every one of the 54 raised this way had its mapped PO in CLOSED. The&lt;br /&gt;
correction therefore had nowhere to land: the GRN completed against the original, nothing was ever&lt;br /&gt;
received against the correction, and it sat holding a reservation for stock that was not coming.&lt;br /&gt;
Backdated by nature, it also parked in INIT under the old approval gate, so it could not have been&lt;br /&gt;
received even if anyone tried.&lt;br /&gt;
&lt;br /&gt;
Resolving a mismatch against a closed PO now says so and names it, asking for that purchase order&lt;br /&gt;
to be reopened first, rather than silently creating a second PO that cannot be used.&lt;br /&gt;
&lt;br /&gt;
WarehousePurchaseOrder.isOpen() names the open set - INIT, READY, PARTIALLY_FULFILLED - that the&lt;br /&gt;
movement and commitment queries already read, so it stops being restated per caller.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/warehouse/WarehousePurchaseOrder.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/GrnRequestServiceImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37703&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37703&amp;peg=37708</guid></item>
<item><pubDate>Fri, 18 Sep 2026 04:06:59 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37702 – Internal movement: an unapproved PO no longer dispatches stock  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Internal movement: an unapproved PO no longer dispatches stock&lt;br /&gt;
&lt;br /&gt;
A PO raised on one of our own warehouses also raises the order that moves the stock, and that&lt;br /&gt;
order pays and processes immediately - so raising it ships goods. The approval gate never&lt;br /&gt;
governed that half. It set the PO to INIT and mailed an approval link, then created and processed&lt;br /&gt;
the order anyway, several lines later and without consulting the status it had just set. The gate&lt;br /&gt;
held back receiving - PO list, GRN matching, auto-close all skip INIT - while dispatch went ahead&lt;br /&gt;
unconditionally.&lt;br /&gt;
&lt;br /&gt;
That is how PO/07-26/52029 was delivered and invoiced while frozen out of GRN. Its goods had to be&lt;br /&gt;
received against a second PO raised for the purpose, leaving the first holding a phantom&lt;br /&gt;
unfulfilled quantity for two months.&lt;br /&gt;
&lt;br /&gt;
Order creation now waits on approval. WarehousePurchaseOrder.isApproved() names the rule once -&lt;br /&gt;
INIT is the only state before approval, every other state is something the order has already been&lt;br /&gt;
approved to do - matching how the PO list, GRN matching and the auto-close sweep already read it,&lt;br /&gt;
so callers stop restating it.&lt;br /&gt;
&lt;br /&gt;
Backdated POs are approved at creation since r37682, so this holds nothing up today; it is what&lt;br /&gt;
keeps the two halves from separating again if any future rule leaves a PO unapproved. Nothing&lt;br /&gt;
raises the order later, so such a PO simply does not move stock and has to be raised again once&lt;br /&gt;
approved - the safe failure, and it is logged.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/warehouse/WarehousePurchaseOrder.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=37702&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37702&amp;peg=37708</guid></item>
<item><pubDate>Fri, 18 Sep 2026 01:05:24 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37701 – PO create: expected stock counts toward the quantity, popover wording ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;PO create: expected stock counts toward the quantity, popover wording follows&lt;br /&gt;
&lt;br /&gt;
Stock still to arrive is now part of what the order can take, so the breakdown reports it as a&lt;br /&gt;
qualifier on that number rather than as something set aside - &apos;Of these, still to arrive&apos; instead&lt;br /&gt;
of &apos;On the way in (not yet received)&apos;, which read as though it could not be ordered.&lt;br /&gt;
&lt;br /&gt;
Tests follow the two rule changes: expected receipts can be ordered against, a quantity beyond&lt;br /&gt;
what is held and expected together is still refused and says so, and availability counts expected&lt;br /&gt;
receipts toward what can move. 21 tests pass.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/warehouse-purchase.js&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=37701&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37701&amp;peg=37708</guid></item>
<item><pubDate>Fri, 18 Sep 2026 01:05:17 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37700 – Internal movement: order against expected stock, and stop reserving lines ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;Internal movement: order against expected stock, and stop reserving lines that can no longer ship&lt;br /&gt;
&lt;br /&gt;
Two rules changed, both about stock that was being treated as unavailable when it is not.&lt;br /&gt;
&lt;br /&gt;
Stock still to arrive now counts toward what a movement order can be raised for. A movement is&lt;br /&gt;
planned against what the warehouse will hold, so the order is raised now and dispatched once the&lt;br /&gt;
stock lands; previously a warehouse holding only inbound stock refused outright, even though the&lt;br /&gt;
receipt was already on an open order.&lt;br /&gt;
&lt;br /&gt;
A purchase order line stops reserving stock once its own order moves past being submitted for&lt;br /&gt;
processing. Billed or shipped means the units have already come off the shelf; cancelled means&lt;br /&gt;
the line can never dispatch them. Holding either back a second time hid stock that was genuinely&lt;br /&gt;
free - on prod, 660 of 675 reserved units were on lines whose orders had already moved on. A line&lt;br /&gt;
whose order has not been raised at all is still a live promise and keeps its hold, and a line is&lt;br /&gt;
held only for the quantity still sitting in an in-process order, so a partly-shipped order&lt;br /&gt;
releases the rest.&lt;br /&gt;
&lt;br /&gt;
priceFor and describeAvailability continue to read stock through one shared examine(), so what is&lt;br /&gt;
shown while choosing a quantity stays exactly what the order is created against.&lt;/div&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/warehouse/WarehouseInventoryItemRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/InternalMovementPricingServiceImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37700&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37700&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 22:56:54 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37699 – Fix: movement availability popover rendered empty except the closing note ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;Fix: movement availability popover rendered empty except the closing note&lt;br /&gt;
&lt;br /&gt;
The breakdown was built as a table. Bootstrap 3.4.1 sanitizes popover content against a&lt;br /&gt;
whitelist that includes neither table nor its rows and cells, and it removes a non-whitelisted&lt;br /&gt;
element together with everything inside it - so the whole table was dropped and only the note&lt;br /&gt;
survived, leaving a popover that referred to orders that were not shown.&lt;br /&gt;
&lt;br /&gt;
Rebuilt from divs and spans, which are whitelisted. Sanitizing stays on rather than being&lt;br /&gt;
switched off for this popover: the content carries PO numbers and warehouse names read out of&lt;br /&gt;
the database.&lt;br /&gt;
&lt;br /&gt;
Also stops the zero-quantity note pointing at orders that are not there - a warehouse whose&lt;br /&gt;
only stock is still inbound has nothing promised to point at. jsVersion bumped.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/warehouse-purchase.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/warehouse-purchase-order-add-item.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37699&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37699&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 22:46:05 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37698 – V2 getPricing: carry internal movement availability alongside the price  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;V2 getPricing: carry internal movement availability alongside the price&lt;br /&gt;
&lt;br /&gt;
Mirrors the fofo change so the two /getPricing endpoints answer alike. V2 is dormant but&lt;br /&gt;
component-scanned, so it has to keep compiling against the service signature.&lt;/div&gt;~ /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/V2FofoVendorController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37698&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37698&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 22:45:53 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37697 – PO create: show what can move, and which orders hold ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;PO create: show what can move, and which orders hold the rest, while the quantity is typed&lt;br /&gt;
&lt;br /&gt;
Picking an item on a movement order already called getPricing, which read the sending&lt;br /&gt;
warehouse&apos;s stock and returned only a price. It now returns the availability too, so the row&lt;br /&gt;
can show it: an info marker beside the quantity box opens the breakdown - in stock, promised&lt;br /&gt;
with each holding order named by PO number and date, anything still arriving, and the quantity&lt;br /&gt;
this order can take.&lt;br /&gt;
&lt;br /&gt;
The quantity box flags the moment what is typed passes that cap, so it is corrected before&lt;br /&gt;
submitting rather than after being refused. The marker turns amber when stock is partly&lt;br /&gt;
promised and red when none can move.&lt;br /&gt;
&lt;br /&gt;
Outside vendors are unaffected: their pricing response carries no availability and their rows&lt;br /&gt;
are left exactly as they were. jsVersion bumped so the screen picks up the new script.&lt;br /&gt;
&lt;br /&gt;
Tests cover the four cases that matter: what can move with orders named, zero movable reported&lt;br /&gt;
rather than refused, this order&apos;s cap kept separate from what the warehouse holds when stock&lt;br /&gt;
came in at two costs, and a warehouse holding none of the item still refusing.&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/VendorController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/warehouse-purchase.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/warehouse-purchase-order-add-item.vm&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=37697&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37697&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 22:45:33 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37696 – Internal movement: report what a warehouse can actually send, not ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 6 file(s) modified&lt;/strong&gt;&lt;br/&gt;Internal movement: report what a warehouse can actually send, not just refuse on submit&lt;br /&gt;
&lt;br /&gt;
The quantity a movement order can take was only discovered by submitting the order and being&lt;br /&gt;
refused. The stock reading that decides it already computed everything needed to say so in&lt;br /&gt;
advance - what is on the shelf, what older orders have promised, what is still arriving - and&lt;br /&gt;
then discarded it.&lt;br /&gt;
&lt;br /&gt;
selectOpenOutboundCommitments returns those promises one row per order, with the PO number,&lt;br /&gt;
PO date and destination, instead of a single summed quantity. applyOutboundCommitments now&lt;br /&gt;
aggregates those rows and behaves exactly as before, so no extra query is run.&lt;br /&gt;
&lt;br /&gt;
describeAvailability answers with the price plus that working. It shares one stock reading with&lt;br /&gt;
priceFor via examine(), so the cap shown while choosing a quantity and the cap enforced on&lt;br /&gt;
submit cannot drift apart. Unlike pricing it reports rather than refuses: stock that is entirely&lt;br /&gt;
promised comes back as zero movable with the orders holding it named, which is what lets someone&lt;br /&gt;
chase an abandoned order rather than only see a smaller number.&lt;/div&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/model/InternalMovementAvailabilityModel.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/model/MovementCommitmentModel.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/InternalMovementPricingService.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/InternalMovementPricingServiceImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37696&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37696&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 18:19:29 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37695 – test(warehouse): cost layer tests; update movement tests for cost-based allocation ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;test(warehouse): cost layer tests; update movement tests for cost-based allocation&lt;br /&gt;
&lt;br /&gt;
- InventoryCostLayerTest: local-DB tests for layers vs stock on hand, movement priced at recorded cost, refusal across costs, promised stock held back, pending inbound offered but not dispatchable, and GRN recording vendor and cost&lt;br /&gt;
- InternalMovementPricingServiceTest: layers now keyed by cost, so same-cost stock moves together and a different cost needs its own order&lt;br /&gt;
- BillingPricingServiceTest: compare against recorded origins rather than the serial-trace source&lt;/div&gt;~ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/service/warehouse/BillingPricingServiceTest.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/service/warehouse/InternalMovementPricingServiceTest.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/service/warehouse/InventoryCostLayerTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37695&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37695&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 18:19:28 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37694 – feat(warehouse): record where stock came from and what it cost; ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 11 file(s) modified&lt;/strong&gt;&lt;br/&gt;feat(warehouse): record where stock came from and what it cost; price internal movements at that cost&lt;br /&gt;
&lt;br /&gt;
- inventoryItem.origin_vendor_id / receipt_unit_cost and lineitem.origin_vendor_id (sql/add_inventory_cost_layer_20260917.sql, applied on prod 2026-09-17 in 75s): GRN copies both from the PO line it arrived on, so origin survives any number of hops and non-serialised stock keeps it too. Unknowable origin stays NULL - never a guess, never an internal supplier&lt;br /&gt;
- A movement now moves stock at the cost it was received at, not the origin vendor&apos;s current catalog TP. Layers are grouped by cost; a quantity spanning two costs is refused with both numbers, since a PO line carries one price&lt;br /&gt;
- Stock already promised on open outbound movement orders is no longer offered again (176 item/warehouse pairs on prod are fully promised today)&lt;br /&gt;
- Stock on open inbound POs is offered for planning at that order&apos;s price and reported as &apos;on the way in&apos;, but cannot be dispatched until received; the PO item picker lists those items too&lt;br /&gt;
- Backfill: 4,010 of 4,646 in-stock rows on prod got origin and cost; 636 stay unknown and are priced from the latest approved external catalog price as before&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/warehouse/WarehouseInventoryItem.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/warehouse/WarehouseLineItem.java&lt;br /&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/warehouse/WarehouseInventoryItemRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/warehouse/WarehouseLineItemRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/warehouse/WarehouseLineItemRepositoryImpl.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/PurchaseOrderServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/WarehouseServiceImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/add_inventory_cost_layer_20260917.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37694&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37694&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 18:16:36 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37693 – rbm ranking mailer</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm ranking mailer&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/migrations/RunOnceTasks.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37693&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37693&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 18:12:13 +0530</pubDate><dc:creator>vikas</dc:creator><title>Rev 37692 – LMS + Airtel Calling</title><description>&lt;div&gt;&lt;strong&gt;vikas – 9 file(s) modified&lt;/strong&gt;&lt;br/&gt;LMS + Airtel Calling&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/dtr/LeadRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/dtr/LeadRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/LmsDashboardService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/LmsDashboardController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/LmsLeadController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/lms-dashboard.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/include-scripts.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/lead-record.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/lms-dashboard-standalone.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37692&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37692&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 18:11:39 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37691 – rbm rankijng mail</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm rankijng mail&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/migrations/RunOnceTasks.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37691&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37691&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 18:01:08 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37690 – notification scheduler</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;notification scheduler&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/migrations/RunOnceTasks.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37690&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37690&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 18:00:04 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37689 – notification scheduler</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;notification scheduler&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/migrations/RunOnceTasks.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37689&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37689&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 17:59:10 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37688 – Record that the counter/privatedealuser rename was applied on hadb1 (suffix ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Record that the counter/privatedealuser rename was applied on hadb1 (suffix _dropped_20260917)&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/resources/sql/retire_counter_privatedealuser_20260916.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37688&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37688&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 17:59:01 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37687 – rbm ranking mailer</title><description>&lt;div&gt;&lt;strong&gt;ranu – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm ranking mailer&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/migrations/RunOnceTasks.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37687&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37687&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 17:56:53 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37686 – for rbm ranking mail on month end</title><description>&lt;div&gt;&lt;strong&gt;ranu – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;for rbm ranking mail on month end&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/migrations/RunOnceTasks.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/monitors&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/monitors/RbmPerformanceRankingService.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/monitors/RbmPerformanceRankingServiceImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37686&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37686&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 17:53:41 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37685 – Remove selenium from the fofo portal entirely  No browser ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 7 file(s) modified&lt;/strong&gt;&lt;br/&gt;Remove selenium from the fofo portal entirely&lt;br /&gt;
&lt;br /&gt;
No browser starts in this WAR any more, and the selenium-java and&lt;br /&gt;
webdrivermanager dependencies are gone with it. Verified: no source reference to&lt;br /&gt;
selenium/WebDriver/ChromeDriver anywhere in the module, and zero selenium&lt;br /&gt;
artifacts on the runtime classpath.&lt;br /&gt;
&lt;br /&gt;
Three pieces:&lt;br /&gt;
&lt;br /&gt;
1. The insights schedule and its pull move to profitmandi-cron (r37684) and dao&lt;br /&gt;
   (r37683). This service keeps only the READ paths -- redis, then in-memory,&lt;br /&gt;
   then cs.agent_daily_insight -- plus refreshInsights(), which now asks the dao&lt;br /&gt;
   sync service to run once and re-reads what it wrote. The portal therefore&lt;br /&gt;
   holds no credentials at all: KNOWLARITY_USERNAME/PASSWORD are deleted from&lt;br /&gt;
   this source, along with INSIGHTS_PAGE_URL and the 200-character CSS selector&lt;br /&gt;
   the scrape depended on.&lt;br /&gt;
&lt;br /&gt;
2. KnowlarityScraperService deleted. It was dead, not merely idle: zero&lt;br /&gt;
   references anywhere, both @Scheduled annotations commented out, and its&lt;br /&gt;
   @PostConstruct selenium block commented out with the note &apos;DISABLED - Live&lt;br /&gt;
   status now comes from WebSocket via profitmandi-cron&apos;. SVN backs that up --&lt;br /&gt;
   r36057/r36058 (25-Mar) moved agent status to the websocket and r36072/r36075&lt;br /&gt;
   (26-Mar) created KnowlarityBreakLogService in dao, but nobody removed the&lt;br /&gt;
   corpse. It kept selenium in this WAR for six months after nothing used it.&lt;br /&gt;
   The data agrees: &apos;On Break - &amp;lt;reason&gt;&apos; rows in cs.rbm_break_log stop on&lt;br /&gt;
   25-27 March and plain &apos;Break&apos; takes over, which is exactly that handover.&lt;br /&gt;
&lt;br /&gt;
   ⚠ Consequence worth knowing: break-REASON granularity (lunch/meeting/sick)&lt;br /&gt;
   was lost at that migration and is not coming back from the websocket feed.&lt;br /&gt;
&lt;br /&gt;
3. setTokens() and POST /indent/set_knowlarity_tokens removed -- the method had&lt;br /&gt;
   already been reduced to a log line, and the pull now authenticates itself per&lt;br /&gt;
   run. Also retired the orphan knowlarity.scraper.enabled property (nothing read&lt;br /&gt;
   it; it was still &apos;true&apos; in prod), and corrected a stale section header and a&lt;br /&gt;
   doc comment that promised &apos;current tokens&apos; which no longer exist.&lt;br /&gt;
&lt;br /&gt;
Not touched, deliberately: POST update_agent_status / bulk_update_agent_status /&lt;br /&gt;
update_status_by_name still exist and still write cs.rbm_break_log through&lt;br /&gt;
AgentLiveStatusService. They are orphaned -- the deleted scraper was their only&lt;br /&gt;
feeder and no view or script in the deployed WAR calls them -- but they are&lt;br /&gt;
public HTTP surface, so proving there is no INTERNAL caller is not the same as&lt;br /&gt;
proving no external one. Left for a separate decision.&lt;/div&gt;~ /trunk/profitmandi-fofo/build.gradle&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/monitors/MonitorController.java&lt;br /&gt;x /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/service/KnowlarityApiClient.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/service/KnowlarityInsightsService.java&lt;br /&gt;x /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/service/KnowlarityScraperService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/resources/META-INF/dev.properties&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/resources/META-INF/prod.properties&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37685&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37685&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 17:53:22 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37684 – Schedule the knowlarity insights pull here instead of in the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Schedule the knowlarity insights pull here instead of in the fofo tomcat&lt;br /&gt;
&lt;br /&gt;
Eight times a day, unchanged times (11:40, 13:40, 15:40, 17:40, 18:40, 19:15,&lt;br /&gt;
20:00, 20:40) so the shape of the day&apos;s data does not move. Calls&lt;br /&gt;
KnowlarityInsightsSyncService (dao r37683).&lt;br /&gt;
&lt;br /&gt;
This lands next to KnowlarityCallMonitorScheduler on purpose: that one owns the&lt;br /&gt;
WebSocket status feed into cs.rbm_break_log, this one owns the periodic KPI pull&lt;br /&gt;
into cs.agent_daily_insight. They are the two halves of the same integration and&lt;br /&gt;
were previously split across two processes for no reason other than history.&lt;br /&gt;
&lt;br /&gt;
What it replaces: the same schedule inside the fofo tomcat, where every run&lt;br /&gt;
started an ~850MB headless chrome on a box that holds a -Xmx8g tomcat and a&lt;br /&gt;
-Xmx2g cron jar on 16GB and has been kernel-OOM-killed twice. A run is now four&lt;br /&gt;
HTTPS calls, ~2-3 seconds.&lt;br /&gt;
&lt;br /&gt;
⚠ Only fires under --spring.profiles.active=scheduled; a one-shot CLI run does&lt;br /&gt;
not start the schedulers.&lt;br /&gt;
&lt;br /&gt;
staging.properties gains the knowlarity block. It had NO knowlarity keys at all,&lt;br /&gt;
which means the WebSocket call monitor has never run there either -- this fixes&lt;br /&gt;
both. Same credentials as prod; there is no separate SR tenant for staging.&lt;br /&gt;
&lt;br /&gt;
Cadence is worth revisiting separately: the 8 slots were chosen when a run cost&lt;br /&gt;
75 seconds and 850MB. At 2 seconds, hourly or every 15 minutes during the&lt;br /&gt;
10:00-21:00 window (matching the call monitor) would be nearly free.&lt;/div&gt;+ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/knowlarity/KnowlarityInsightsScheduler.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/resources/META-INF/staging.properties&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37684&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37684&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 17:53:09 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37683 – Move the knowlarity insights pull into dao, and delete the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 6 file(s) modified&lt;/strong&gt;&lt;br/&gt;Move the knowlarity insights pull into dao, and delete the dead earlier attempt&lt;br /&gt;
&lt;br /&gt;
The pull belongs in dao because its SCHEDULE moves to profitmandi-cron while the&lt;br /&gt;
fofo portal still reads the same rows. Both modules depend on dao, so that is the&lt;br /&gt;
only place the two can share it.&lt;br /&gt;
&lt;br /&gt;
KnowlarityInsightsSyncService fetches via KnowlarityApiClient (moved here from&lt;br /&gt;
fofo, unchanged) and upserts cs.agent_daily_insight. No DDL: every column it&lt;br /&gt;
writes already exists.&lt;br /&gt;
&lt;br /&gt;
It writes what the old chrome scrape could not:&lt;br /&gt;
 - the *_seconds columns. Verified on prod over 7 consecutive days, every row had&lt;br /&gt;
   logged_in_seconds, break_seconds, available_seconds and talk_seconds = 0. The&lt;br /&gt;
   API returns fractional seconds as numbers, so they are stored directly rather&lt;br /&gt;
   than re-parsed out of a display string.&lt;br /&gt;
 - calls_answered / missed_calls / total_calls, also 0 on every row, because the&lt;br /&gt;
   scrape never captured them at all.&lt;br /&gt;
&lt;br /&gt;
auth_id resolution keeps the email-PREFIX match from the fofo version: some&lt;br /&gt;
stored emails are truncated (&apos;&lt;a href=&quot;mailto:user@smartdukaan.co&quot;&gt;user@smartdukaan.co&lt;/a&gt;..&apos;), so matching the whole&lt;br /&gt;
address silently misses those agents.&lt;br /&gt;
&lt;br /&gt;
Redis keys are deliberately the same pair the portal reads, so its fast path&lt;br /&gt;
stays warm across the process boundary. ⚠ That makes AgentInsightRow&apos;s getter&lt;br /&gt;
names a contract with fofo&apos;s AgentInsightDTO -- rename one without the other and&lt;br /&gt;
the portal deserialises blanks.&lt;br /&gt;
&lt;br /&gt;
Also deleted, all with zero external references:&lt;br /&gt;
 - KnowlarityAgentInsightsService: an earlier, unfinished run at this same API.&lt;br /&gt;
   Its ALT_INSIGHTS_APIS list of guessed endpoints is the giveaway that it never&lt;br /&gt;
   worked; nothing ever called it. It owned three redis keys nobody read&lt;br /&gt;
   (knowlarity:agent:insights, :summary, :lastUpdate) -- distinct from the live&lt;br /&gt;
   knowlarity:insights:* pair, which stays.&lt;br /&gt;
 - AgentInsightsDTO / AgentInsightsSummaryDTO: used only by that service.&lt;br /&gt;
 - KnowlaritySocketTest: a scratch main(), never referenced.&lt;/div&gt;x /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/knowlarity/dto/AgentInsightsDTO.java&lt;br /&gt;x /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/knowlarity/dto/AgentInsightsSummaryDTO.java&lt;br /&gt;x /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/knowlarity/KnowlarityAgentInsightsService.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/knowlarity/KnowlarityApiClient.java &lt;i&gt;(copied from /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/service/KnowlarityApiClient.java@37682)&lt;/i&gt;&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/knowlarity/KnowlarityInsightsSyncService.java&lt;br /&gt;x /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/knowlarity/KnowlaritySocketTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37683&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37683&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 16:40:41 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37682 – feat(warehouse): auto-approve backdated POs in the creator&apos;s name  A ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;feat(warehouse): auto-approve backdated POs in the creator&apos;s name&lt;br /&gt;
&lt;br /&gt;
A backdated PO used to be parked in POStatus.INIT until an HOD clicked a mailed approval link. INIT&lt;br /&gt;
keeps a PO out of the PO list, out of GRN/invoice matching and out of the auto-close sweep, so an&lt;br /&gt;
unclicked PO was frozen rather than merely pending - 440 had accumulated since 2024, of 2547 approval&lt;br /&gt;
rows only 2023 were ever clicked.&lt;br /&gt;
&lt;br /&gt;
- every PO now goes READY at creation, backdated or not&lt;br /&gt;
- the warehouse.poapproval row is still written, stamped approvedOn=now and approvedBy=&amp;lt;creator&gt; by&lt;br /&gt;
  recordAutoApproval(), since that row is what identifies a PO as backdated and who backdated it&lt;br /&gt;
- the HOD mail survives as a notification: names the creator, no approval link, PDF still attached&lt;br /&gt;
- /approve-po-date/* endpoints kept so links already sent do not 404&lt;br /&gt;
&lt;br /&gt;
Completes r37679-81. Backfill for the three POs still inside POScheduler&apos;s window is staged at&lt;br /&gt;
profitmandi-dao/src/main/resources/sql/backdated_po_auto_approval_backfill_20260917.sql, not run.&lt;/div&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=37682&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37682&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 16:29:18 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37681 – feat(warehouse): resolve the logged-in user on V2 PO creation and ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;feat(warehouse): resolve the logged-in user on V2 PO creation and GRN mismatch resolution&lt;br /&gt;
&lt;br /&gt;
V2 mirror of r37680, keeping the dormant V2 controllers in step with the fofo MVC ones.&lt;br /&gt;
&lt;br /&gt;
- createPurchaseOrder resolves the logged-in user via getEmailId + authRepository and sets createdBy&lt;br /&gt;
- resolvedMismatchRequest passes the resolver through&lt;br /&gt;
&lt;br /&gt;
Pairs with r37679.&lt;/div&gt;~ /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/V2FofoGrnController.java&lt;br /&gt;~ /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/V2FofoPurchaseOrderController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37681&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37681&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 16:29:12 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37680 – feat(warehouse): resolve the logged-in user on PO creation and GRN ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;feat(warehouse): resolve the logged-in user on PO creation and GRN mismatch resolution&lt;br /&gt;
&lt;br /&gt;
Backdated POs are auto-approved in their creator&apos;s name, so the user has to travel with the request.&lt;br /&gt;
&lt;br /&gt;
- createPurchaseOrder resolves the logged-in user via cookiesProcessor + authRepository and sets createdBy&lt;br /&gt;
- resolvedMismatchRequest passes the resolver through, for the correction PO it can raise&lt;br /&gt;
- PO create page no longer says backdated POs need HOD approval&lt;br /&gt;
&lt;br /&gt;
Pairs with r37679.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/warehouse/GrnController.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/main/webapp/WEB-INF/views/ftl/warehouse-create-purchase-order.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37680&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37680&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 16:29:06 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37679 – feat(warehouse): carry the PO creator through purchase order creation for ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;feat(warehouse): carry the PO creator through purchase order creation for backdated auto-approval&lt;br /&gt;
&lt;br /&gt;
Backdated POs are to be auto-approved in the name of whoever raised them, but the service had no way&lt;br /&gt;
to know who that was: the model carried no user and buyerId is the seller, not a person.&lt;br /&gt;
&lt;br /&gt;
- CreateWarehousePurchaseOrderModel carries createdBy&lt;br /&gt;
- resolvedMismatchRequest takes resolvedBy, so the correction PO raised on a GRN price mismatch -&lt;br /&gt;
  dated to the supplier invoice and therefore backdated by nature - is credited to whoever resolved it&lt;br /&gt;
- staged backfill SQL for the three backdated POs still stuck in INIT inside POScheduler&apos;s&lt;br /&gt;
  auto-close window; data only, no schema change, not yet run&lt;br /&gt;
&lt;br /&gt;
The release-to-READY change in PurchaseOrderServiceImpl follows separately.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/model/CreateWarehousePurchaseOrderModel.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/warehouse/GrnRequestService.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/resources/sql/backdated_po_auto_approval_backfill_20260917.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37679&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37679&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 15:55:49 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37678 – Replace the knowlarity insights chrome scrape with SR&apos;s own JSON ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Replace the knowlarity insights chrome scrape with SR&apos;s own JSON API&lt;br /&gt;
&lt;br /&gt;
Drops the last unattended headless chrome out of the fofo tomcat. The scheduled&lt;br /&gt;
insights job ran 8 times a day and each run started an ~850MB chrome tree inside&lt;br /&gt;
the tomcat JVM&apos;s host -- a box holding -Xmx8g tomcat plus a -Xmx2g cron jar on&lt;br /&gt;
16GB that has been kernel-OOM-killed twice with tomcat the victim.&lt;br /&gt;
&lt;br /&gt;
It was also losing data the whole time. Verified on prod across 7 consecutive&lt;br /&gt;
days: every row of cs.agent_daily_insight has logged_in_seconds, break_seconds,&lt;br /&gt;
available_seconds, talk_seconds, calls_answered, missed_calls and total_calls&lt;br /&gt;
set to 0. Two separate causes, both fixed here:&lt;br /&gt;
&lt;br /&gt;
 - parseTimeToSeconds split on &apos;:&apos; expecting &apos;HH:mm:ss&apos;, but the table renders&lt;br /&gt;
   &apos;2h 50m 39s&apos;. A one-element split fell through to return 0, and because it&lt;br /&gt;
   never reached the NumberFormatException branch it did not even warn. It now&lt;br /&gt;
   parses the h/m/s shape and still accepts HH:mm:ss and HH:mm.&lt;br /&gt;
 - the scrape never captured the call counts at all. The API carries them.&lt;br /&gt;
&lt;br /&gt;
The auth chain is four calls and is not guessable, so it is documented in&lt;br /&gt;
KnowlarityApiClient: POST /vr/sr_login/ establishes the session and returns an&lt;br /&gt;
HS256 token that the API REJECTS; GET /newsr/user_details yields new_sr_ui_url&lt;br /&gt;
carrying a one-shot SSO blob (in a browser this hop is javascript, so it is&lt;br /&gt;
invisible to anything that merely follows redirects); POST /vr/sso_login/&lt;br /&gt;
exchanges that blob for the RS256 token the API accepts, whose claims embed the&lt;br /&gt;
srsessionid and so bind it to the session; GET /newsr/agents_insights/ with&lt;br /&gt;
header jwtAuthorization. Wrong token and wrong header name both answer&lt;br /&gt;
&apos;Invalid token&apos;, so the error never tells you which mistake you made. The window&lt;br /&gt;
parameters are start_time/end_time -- start_date/end_date authenticates fine and&lt;br /&gt;
returns &apos;Error in  API&apos;.&lt;br /&gt;
&lt;br /&gt;
Redirects are followed BY HAND. setInstanceFollowRedirects(true) exposes only&lt;br /&gt;
the final response&apos;s headers, so the Set-Cookie issued on the intermediate hops&lt;br /&gt;
is lost, the session never forms and user_details answers with an HTML error&lt;br /&gt;
page. This cost a debugging cycle; the reason is commented at the call site.&lt;br /&gt;
&lt;br /&gt;
Verified against the live account before committing: 13 agents returned,&lt;br /&gt;
calls_offered == calls_answered + missed_calls holds for all 13, durations match&lt;br /&gt;
the previous scrape to within the elapsed window (~55s), and formatSeconds /&lt;br /&gt;
parseTimeToSeconds round-trip cleanly over the real values.&lt;br /&gt;
&lt;br /&gt;
DTO fields stay the same display strings (&apos;2h 50m 39s&apos;), so every existing&lt;br /&gt;
reader is unaffected; only the previously-zero numeric columns change.&lt;br /&gt;
&lt;br /&gt;
KnowlarityScraperService still uses ChromeDriver for operator-triggered break-log&lt;br /&gt;
scrapes, so the selenium dependency stays for now. Its @Scheduled annotations are&lt;br /&gt;
already commented out, so nothing unattended starts a browser any more.&lt;/div&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/service/KnowlarityApiClient.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/service/KnowlarityInsightsService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37678&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37678&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 15:26:23 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37677 – price drop and hike fixed</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;price drop and hike fixed&lt;/div&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=37677&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37677&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 15:19:50 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37676 – v2 version some fixes</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;v2 version some fixes&lt;/div&gt;~ /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/controller/DealsController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37676&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37676&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 14:52:14 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37675 – Remove the dead Samsung and Amazon Selenium paths  Both ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;Remove the dead Samsung and Amazon Selenium paths&lt;br /&gt;
&lt;br /&gt;
Both were manual one-shots that nothing runs any more, and each started an&lt;br /&gt;
850MB chrome tree that now has to queue on the browser lane, so they are cost&lt;br /&gt;
without a caller.&lt;br /&gt;
&lt;br /&gt;
Evidence they are dead rather than merely idle:&lt;br /&gt;
 - No crontab entry, no cron.d file and no script references --samsung or&lt;br /&gt;
   --amazonPurchase, and neither flag appears even once in cron.log.&lt;br /&gt;
 - fofo.activated_imei has ZERO Samsung rows written by the cron (auth_id 0) in&lt;br /&gt;
   the last 90 days. All 2,331 Samsung rows in that window are auth_id 307, i.e.&lt;br /&gt;
   the human CSV upload, most recently 16-Sep. The scraper is not what keeps&lt;br /&gt;
   Samsung current; people are.&lt;br /&gt;
 - ScheduledSkeleton.fetchImeiActivation() had already been retired in place --&lt;br /&gt;
   its @Scheduled was commented out with &apos;No longer scheduled&apos;.&lt;br /&gt;
 - RunOnceTasks.amazonPurchase() reads /Users/amit/Downloads/amazon.xlsx, a&lt;br /&gt;
   laptop path that cannot exist on the server.&lt;br /&gt;
&lt;br /&gt;
Removed: SamsungIMEIActivationService, the whole scheduled/amazon package&lt;br /&gt;
(AmazonPurchaseService, OrderSummary, OrderRow, AmazonUser), their RunOnceTasks&lt;br /&gt;
callers and helpers (fetchImeiActivation, amazonPurchase, getOrderSummary,&lt;br /&gt;
parseRow), the two Application CLI blocks and the retired ScheduledSkeleton&lt;br /&gt;
wrapper. The amazon package had no importers outside RunOnceTasks.&lt;br /&gt;
&lt;br /&gt;
Both also leaked a chrome profile dir on every run -- AmazonPurchaseService&lt;br /&gt;
never called quit() at all, and SamsungIMEIActivationService called it outside&lt;br /&gt;
any finally -- so this removes two leak sources rather than fixing them.&lt;br /&gt;
&lt;br /&gt;
Untouched: RunOnceTasks.mailDashboardScreenshots() is a third dead Selenium&lt;br /&gt;
one-shot (also zero invocations) but it mails a report, so it is left for a&lt;br /&gt;
separate decision.&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/migrations/RunOnceTasks.java&lt;br /&gt;x /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/amazon&lt;br /&gt;x /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/SamsungIMEIActivationService.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=37675&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37675&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 13:13:15 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37674 – Hold the browser lane around the knowlarity scrapes  These ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Hold the browser lane around the knowlarity scrapes&lt;br /&gt;
&lt;br /&gt;
These run Chrome inside the tomcat JVM, on the same box as the cron jar&apos;s&lt;br /&gt;
oppo/realme imei lane, with nothing coordinating the two. isScraping only guards&lt;br /&gt;
this JVM and cannot see the cron&apos;s driver, so the interlock has to be the&lt;br /&gt;
OS-level one -- BrowserLane, common r37672.&lt;br /&gt;
&lt;br /&gt;
Fifteen minutes rather than the cron side&apos;s five: the insights scrape runs only&lt;br /&gt;
8 times a day against a lane that is busy ~96% of the time, so a short timeout&lt;br /&gt;
here would mean the insights never refreshed. On contention it serves cache.&lt;br /&gt;
&lt;br /&gt;
The break-log scraper takes the lane around its freshDriver, which has a clean&lt;br /&gt;
try/finally bracket. setupDriver()&apos;s long-lived field driver is deliberately left&lt;br /&gt;
alone -- its lifetime spans init to @PreDestroy and holding an OS lock that long&lt;br /&gt;
would starve the imei lane.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/service/KnowlarityInsightsService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/service/KnowlarityScraperService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37674&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37674&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 13:13:07 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37673 – Hold the browser lane around the oppo/realme/motorola drivers  Takes ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;Hold the browser lane around the oppo/realme/motorola drivers&lt;br /&gt;
&lt;br /&gt;
Takes BrowserLane (common r37672) before new ChromeDriver and releases it after&lt;br /&gt;
quit() returns -- the 850MB is resident for the whole chunk, not just at&lt;br /&gt;
startup, so bracketing only the constructor would protect nothing.&lt;br /&gt;
&lt;br /&gt;
Five minutes of waiting, then give up and return what we have: the only things&lt;br /&gt;
that can hold the lane that long are the other brand mid-chunk or the knowlarity&lt;br /&gt;
scrape in the fofo tomcat, and giving up costs nothing because an unstamped imei&lt;br /&gt;
stays pending and the lane&apos;s next turn picks it up.&lt;br /&gt;
&lt;br /&gt;
CheckMotorolaWarrantyTask carries a comment saying &apos;do not let this job overlap&lt;br /&gt;
the oppo/realme window&apos; that nothing ever enforced. It is wired here too so it is&lt;br /&gt;
already safe whenever it gets a trigger -- it still has none today.&lt;br /&gt;
&lt;br /&gt;
Note on sizing, since the obvious knob is the wrong one: shrinking CHUNK from 25&lt;br /&gt;
was evaluated and rejected. The idle window is a fixed 20s bolted onto a variable&lt;br /&gt;
work period, so 25-&gt;10 moves the duty cycle only 96% -&gt; 91% while costing 8.4%&lt;br /&gt;
of daily throughput and 2.5x the driver launches. The lever for duty cycle is the&lt;br /&gt;
fixedDelay gap, not the chunk size.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/CheckMotorolaWarrantyTask.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/CheckOppoWarrantyTask.java&lt;br /&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/CheckRealmeWarrantyTask.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37673&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37673&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 13:12:56 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37672 – Add BrowserLane: machine-wide interlock so only one headless Chrome runs ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Add BrowserLane: machine-wide interlock so only one headless Chrome runs at a time&lt;br /&gt;
&lt;br /&gt;
Every ChromeDriver tree on the app box costs ~850MB RSS, on a host holding a&lt;br /&gt;
-Xmx8g tomcat and a -Xmx2g cron jar on 16GB that has been kernel-OOM-killed&lt;br /&gt;
twice with tomcat the victim. Peak concurrent drivers is the number that&lt;br /&gt;
matters, not drivers per day.&lt;br /&gt;
&lt;br /&gt;
Measured on the oppo/realme lane: a 25-imei chunk takes 505s (12s driver&lt;br /&gt;
startup, then ~19.7s an imei) against a fixed 20s fixedDelay, i.e. a 96% duty&lt;br /&gt;
cycle. Meanwhile tomcat starts its own driver 8 times a day for the knowlarity&lt;br /&gt;
scrape. On 17-Sep that scrape ran 11:40:00-11:41:07 and the lane&apos;s next driver&lt;br /&gt;
came up at 11:42:21 -- it cleared by 74 seconds, by luck. At a 96% duty cycle&lt;br /&gt;
the collision cannot be dodged by choosing better times, only by serialising.&lt;br /&gt;
&lt;br /&gt;
The two JVMs are separate processes owned by different users, so an in-process&lt;br /&gt;
flag cannot see across the boundary. Uses an OS file lock at&lt;br /&gt;
/var/lock/sd-browser.lock (overridable via -Dsd.browser.lock), created 0666 on&lt;br /&gt;
first use because cron runs as root and tomcat as tomcat and whichever starts&lt;br /&gt;
first creates it. A file lock rather than a marker file so the kernel reclaims&lt;br /&gt;
it when the holder dies: verified by SIGKILLing the holder mid-hold, the next&lt;br /&gt;
JVM acquired in 264ms. A ReentrantLock gates it first, since a second thread in&lt;br /&gt;
the same JVM would otherwise get OverlappingFileLockException rather than block.&lt;br /&gt;
&lt;br /&gt;
Callers wait rather than skip. The knowlarity scrape needs 67s against a lane&lt;br /&gt;
busy 96% of the time, so skip-on-contention would mean it essentially never&lt;br /&gt;
refreshed again. Eight scrapes a day costs the imei lane about nine minutes of&lt;br /&gt;
waiting in total.&lt;br /&gt;
&lt;br /&gt;
Fails open if the lock file is unusable (missing /var/lock, read-only mount, dev&lt;br /&gt;
laptop): serialising within the JVM only, rather than stopping imei activation&lt;br /&gt;
over what is a safety interlock.&lt;/div&gt;+ /trunk/profitmandi-common/src/main/java/com/spice/profitmandi/common/util/BrowserLane.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37672&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37672&amp;peg=37708</guid></item>
<item><pubDate>Thu, 17 Sep 2026 11:33:22 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37671 – loi revival process modify</title><description>&lt;div&gt;&lt;strong&gt;ranu – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;loi revival process modify&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/user/StoreTimelineTatServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/LoiFormController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37671&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37671&amp;peg=37708</guid></item>
<item><pubDate>Wed, 16 Sep 2026 20:29:46 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37670 – Check GSTIN shape on the onboarding screen before submit (jsVersion ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Check GSTIN shape on the onboarding screen before submit (jsVersion 425)&lt;br /&gt;
&lt;br /&gt;
Both GST boxes are validated client-side and must match, so ops see the problem on the screen&lt;br /&gt;
instead of discovering it when NIC refuses the first invoice. Server-side guard in dao r37669&lt;br /&gt;
is what actually enforces it.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/update-retailer-details.js&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37670&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37670&amp;peg=37708</guid></item>
<item><pubDate>Wed, 16 Sep 2026 20:29:41 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37669 – Reject an invalid or mismatched partner GSTIN before it is ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Reject an invalid or mismatched partner GSTIN before it is saved&lt;br /&gt;
&lt;br /&gt;
The onboarding screen carries the GSTIN in two boxes both labelled GST NUMBER - the retailer&lt;br /&gt;
one (dtr.retailer.number) and the store one (fofo_store.gst_number, which billing reads).&lt;br /&gt;
Neither was validated, so DLSH1660 was saved with the LOI&apos;s pincode in the store box while the&lt;br /&gt;
retailer box held the real GSTIN, and its first invoice would have been refused by NIC.&lt;br /&gt;
&lt;br /&gt;
validateGstNumbers runs before any write (covers the fofo portal, the V2 API and the partner&lt;br /&gt;
app, which all funnel through updateRetailerDetails): both values are normalised, both must be&lt;br /&gt;
valid GSTINs, and when both are present they must agree - across 1,800 partners on record they&lt;br /&gt;
already do, bar the one that caused this. Needs common r37668.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/user/RetailerServiceImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37669&amp;peg=37708</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37669&amp;peg=37708</guid></item>
</channel></rss>