<?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>Mon, 31 Aug 2026 17:20:57 +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;isdir=1&amp;max=40&amp;</link><atom:link href="https://svn.smartdukaan.com/rss.php?isdir=1&amp;repname=SmartDukaan" rel="self" type="application/rss+xml" />
<item><pubDate>Mon, 31 Aug 2026 17:19:03 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37476 – mail: delete the dead SendGrid bean from fofo, make the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;mail: delete the dead SendGrid bean from fofo, make the authenticated identity primary&lt;br /&gt;
&lt;br /&gt;
googleMailSender is now @Primary and answers to &apos;mailSender&apos;. Two senders remain:&lt;br /&gt;
the authenticated Workspace identity and the IP-authorised relay.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37476</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37476</guid></item>
<item><pubDate>Mon, 31 Aug 2026 17:11:39 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37475 – mail: delete the dead SendGrid bean from web, make the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;mail: delete the dead SendGrid bean from web, make the authenticated identity primary&lt;br /&gt;
&lt;br /&gt;
Removes the live SendGrid bean plus two commented-out corpses (an old&lt;br /&gt;
&lt;a href=&quot;mailto:build@shop2020.in&quot;&gt;build@shop2020.in&lt;/a&gt; sender and a dead alias). googleMailSender is now @Primary and&lt;br /&gt;
answers to &apos;mailSender&apos;, so unqualified injections get the working authenticated&lt;br /&gt;
sender instead of one that rejects with 535.&lt;/div&gt;~ /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37475</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37475</guid></item>
<item><pubDate>Mon, 31 Aug 2026 17:11:26 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37474 – mail: delete the dead SendGrid bean from cron, make the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;mail: delete the dead SendGrid bean from cron, make the authenticated identity primary&lt;br /&gt;
&lt;br /&gt;
The @Primary bean named &apos;mailSender&apos; was SendGrid, so every unqualified&lt;br /&gt;
JavaMailSender injection got it -- and SendGrid rejects with 535, which is what&lt;br /&gt;
was failing 10 report/notification cron jobs (dailyTrackingReport,&lt;br /&gt;
monthlyTargetForPartner, sendFeebackSalesAndRbm and others). 420 occurrences in&lt;br /&gt;
one log.&lt;br /&gt;
&lt;br /&gt;
googleMailSender now answers to both &apos;googleMailSender&apos; and &apos;mailSender&apos; and is&lt;br /&gt;
@Primary, so those injections resolve to a sender that works and whose From is&lt;br /&gt;
rewritten to the authenticated identity. No call site changes.&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/MailOutboxScheduler.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37474</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37474</guid></item>
<item><pubDate>Mon, 31 Aug 2026 17:11:25 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37473 – mail: retire the SENDGRID sender label  SendGrid was never ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;mail: retire the SENDGRID sender label&lt;br /&gt;
&lt;br /&gt;
SendGrid was never actually used by the outbox -- resolveSender() already fell&lt;br /&gt;
through to the Workspace relay for it, which is why outbox mail kept working&lt;br /&gt;
while direct JavaMailSender injections failed.&lt;br /&gt;
&lt;br /&gt;
Two senders remain, each named for what it is:&lt;br /&gt;
  GOOGLE - authenticates as &lt;a href=&quot;mailto:sdtech@smartdukaan.com&quot;&gt;sdtech@smartdukaan.com&lt;/a&gt;; AuthenticatedIdentityMailSender&lt;br /&gt;
           rewrites every From to that identity, because Workspace binds an&lt;br /&gt;
           authenticated session to one address and rejects any other with&lt;br /&gt;
           &apos;535 Authorization failed: Authenticated user is not authorized to send mail&apos;&lt;br /&gt;
  RELAY  - Workspace relay, no auth, authorised by source IP, may send as noreply@&lt;br /&gt;
&lt;br /&gt;
Default convenience methods now route to RELAY explicitly rather than through a&lt;br /&gt;
label that named a provider we do not use.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/mail/MailOutboxService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37473</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37473</guid></item>
<item><pubDate>Mon, 31 Aug 2026 16:08:03 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37472 – IMEI activation: one snapshotted daily pass per brand, on one ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 12 file(s) modified&lt;/strong&gt;&lt;br/&gt;IMEI activation: one snapshotted daily pass per brand, on one thread, with per-brand metrics&lt;br /&gt;
&lt;br /&gt;
Four @Scheduled jobs every 5 minutes become two daily passes. Oppo and realme&lt;br /&gt;
share one thread and alternate in 25-imei chunks, so exactly one ChromeDriver is&lt;br /&gt;
alive at a time instead of four; vivo keeps its own thread since it is direct&lt;br /&gt;
HTTP and does not contend for a browser.&lt;br /&gt;
&lt;br /&gt;
The pass snapshots its pool before any browser starts and walks that list to the&lt;br /&gt;
end. It never re-queries, and that is the actual fix. A failed lookup never&lt;br /&gt;
reaches dateMap.put, so no row is written, so createTimestamp is not bumped, so&lt;br /&gt;
the imei was eligible again on the next tick five minutes later. Measured 29-Aug:&lt;br /&gt;
realme issued 4,524 requests against 1,004 distinct imeis -- 4.5 asks each, 78%&lt;br /&gt;
of the day&apos;s budget spent re-asking -- while oppo, which rarely fails, sat at&lt;br /&gt;
1.03. More requests hardened the block, which caused more failures. A pass bounds&lt;br /&gt;
that: a failure costs one retry tomorrow, never one in five minutes.&lt;br /&gt;
&lt;br /&gt;
This supersedes the r37447/r37448/r37449 argument about driver count, which was&lt;br /&gt;
about the wrong variable. That argument blamed realme&apos;s collapse on CPU&lt;br /&gt;
contention pushing the captcha render past the element waits. The logs do not&lt;br /&gt;
support it: on 29-Aug oppo took ZERO canvas timeouts across all 24 hours on the&lt;br /&gt;
same box, same six cores, same driver count, same captcha vendor, load average&lt;br /&gt;
0.9 -- including the 15:00-23:00 window in which realme solved nothing at all.&lt;br /&gt;
Realme&apos;s own canvas wait is 15s against oppo&apos;s 8s, so the longer wait is the one&lt;br /&gt;
expiring. What realme&apos;s timeout rate tracks is its own daily request volume, and&lt;br /&gt;
it resets at midnight: 920/day -&gt; 0.3%, 3,467/day -&gt; 28%, 4,524/day -&gt; 75%. That&lt;br /&gt;
is realme.com declining to serve the widget.&lt;br /&gt;
&lt;br /&gt;
DAYS=0 is deliberate and is not an off-by-one: the pool filter is&lt;br /&gt;
createTimestamp &amp;lt; now().atStartOfDay().minusDays(DAYS), so DAYS=1 measures&lt;br /&gt;
against yesterday midnight and silently yields a two-day cadence, which is what&lt;br /&gt;
oppo and realme were running.&lt;br /&gt;
&lt;br /&gt;
Sizing measured on prod for a midnight start: oppo 4,133 and realme 2,118 imeis,&lt;br /&gt;
11.7h + 8.4h = 20.1 hours of a single thread. It fits with no slack; if the&lt;br /&gt;
&apos;pass finished&apos; counts come in short of &apos;pass starting&apos;, the lever is DAYS=1&lt;br /&gt;
rather than a second thread.&lt;br /&gt;
&lt;br /&gt;
Observability: ImeiActivationGauges publishes the funnel per brand on&lt;br /&gt;
/actuator/prometheus, which alloy already scrapes on this host -- due, churned,&lt;br /&gt;
captcha_shown, captcha_solved, answered, dates_found, errors, run_seconds and&lt;br /&gt;
last_finish_epoch. Each stage fails differently and says what broke. Rates are&lt;br /&gt;
left to PromQL. The stage that matters for health is answered: churned&gt;0 with&lt;br /&gt;
answered==0 is precisely the shape of both silent outages this year (oppo wrote&lt;br /&gt;
nothing for a week; the vivo captcha solver was dead for 46 days). dates_found is&lt;br /&gt;
deliberately NOT a health signal -- when the multi-year backlog drained at the&lt;br /&gt;
end of August, yield fell from ~100% to 2-3% on the same day across all three&lt;br /&gt;
brands with nothing broken.&lt;br /&gt;
&lt;br /&gt;
Nagios cleanup: the Nagios server and every NRPE daemon are gone, so&lt;br /&gt;
WriteToPropertiesFile and the commented-out blocks that fed&lt;br /&gt;
nagios-cron.properties are deleted, and NagiosMonitorTasks is renamed&lt;br /&gt;
BalanceMonitorTasks for the transport it actually uses. Noted there that nothing&lt;br /&gt;
calls it -- there is no @Scheduled entry and no other caller -- which is why both&lt;br /&gt;
balance gauges have always read -1.&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/monitored/BalanceGauges.java&lt;br /&gt;+ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/monitored/BalanceMonitorTasks.java &lt;i&gt;(copied from /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/monitored/NagiosMonitorTasks.java@37471)&lt;/i&gt;&lt;br /&gt;+ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/monitored/ImeiActivationGauges.java&lt;br /&gt;x /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/monitored/NagiosMonitorTasks.java&lt;br /&gt;x /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/properties/WriteToPropertiesFile.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;~ /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/ScheduledTasks.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=37472</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37472</guid></item>
<item><pubDate>Mon, 31 Aug 2026 16:07:40 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37471 – IMEI activation pools: skip stock billed today or yesterday  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;IMEI activation pools: skip stock billed today or yesterday&lt;br /&gt;
&lt;br /&gt;
Both pool named queries now exclude serials whose sale is inside the last 48&lt;br /&gt;
hours -- o.billingTimestamp for the secondary path, fo.createTimestamp for the&lt;br /&gt;
tertiary one. A handset sold in the last two days has essentially never been&lt;br /&gt;
activated yet, so the lookup is spent for nothing: measured on prod, the&lt;br /&gt;
sold-within-180-days cohort returns an activation date on 2.4% (vivo) to 8.4%&lt;br /&gt;
(oppo) of lookups, against 43-97% for stock sold over a year ago.&lt;br /&gt;
&lt;br /&gt;
billedBefore is set in ActivatedImeiRepositoryImpl rather than passed by the&lt;br /&gt;
caller, so no method signature changes and every brand inherits it -- vivo,&lt;br /&gt;
oppo, realme and motorola all draw from these two queries and nothing outside&lt;br /&gt;
profitmandi-cron uses them.&lt;br /&gt;
&lt;br /&gt;
This is correctness rather than capacity: it trims 30 imeis from the oppo pool&lt;br /&gt;
and 9 from realme.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/entity/fofo/ActivatedImei.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/ActivatedImeiRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37471</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37471</guid></item>
<item><pubDate>Mon, 31 Aug 2026 15:50:16 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37470 – Remove dead Itel/Tecno SAP activation services  Both services call ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;Remove dead Itel/Tecno SAP activation services&lt;br /&gt;
&lt;br /&gt;
Both services call SAP OData endpoints that Transsion decommissioned on 2024-11-20:&lt;br /&gt;
&lt;br /&gt;
  ItelImeiActivationService  -&gt; cms.itel-mobile.com:8099/.../ZTERTIARY_SALES_REPRT_SRV&lt;br /&gt;
  TecnoImeiActivation        -&gt; cms.tecno-mobile.com:8099/.../ZTERTIARY_SALES_REPRT_SRV&lt;br /&gt;
&lt;br /&gt;
Both hosts now refuse connections outright (verified from the prod app server).&lt;br /&gt;
That decommissioning is what stopped Itel and Tecno activation ingest within the&lt;br /&gt;
same hour on 2024-11-20; everything since has arrived via manual CSV upload.&lt;br /&gt;
Neither service has produced a row in 21 months and neither can again.&lt;br /&gt;
&lt;br /&gt;
Removed:&lt;br /&gt;
  - both service classes&lt;br /&gt;
  - ScheduledTasks.checkItelImeiActivation / .checkTecnoImeiActivation, their&lt;br /&gt;
    @Autowired fields and imports (the only callers)&lt;br /&gt;
  - the --checkItelImeiActivation / --checkTecnoImeiActivation startup args&lt;br /&gt;
&lt;br /&gt;
Unaffected: ItelImeiActivationNewService and checkItelImeiActivationNew, which&lt;br /&gt;
target the current imwav portal and were fixed in r37467.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/Application.java&lt;br /&gt;x /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/itelImeiActivation/ItelImeiActivationService.java&lt;br /&gt;x /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/itelImeiActivation/TecnoImeiActivation.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=37470</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37470</guid></item>
<item><pubDate>Mon, 31 Aug 2026 13:40:26 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37469 – rbm drr dashboard , all today po rbm view maped</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm drr dashboard , all today po rbm view maped&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=37469</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37469</guid></item>
<item><pubDate>Mon, 31 Aug 2026 13:14:17 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37468 – rbm drr dashboard new ui looks</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm drr dashboard new ui looks&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=37468</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37468</guid></item>
<item><pubDate>Mon, 31 Aug 2026 11:30:33 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37467 – Fix Itel/Tecno activation pull: live session tokens, correct credentials, per-account ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Fix Itel/Tecno activation pull: live session tokens, correct credentials, per-account isolation&lt;br /&gt;
&lt;br /&gt;
The imwav pull has never worked since it replaced the SAP feed. Three defects:&lt;br /&gt;
&lt;br /&gt;
- Login response was discarded and the listing call sent p-auth/utoken values&lt;br /&gt;
  captured by hand in Jul-2023, so every request went out with an expired session.&lt;br /&gt;
  Now takes utoken/urToken from the login response.&lt;br /&gt;
- Itel (IN404338I) carried a stale password (Dukaan@1234), which is why its pull&lt;br /&gt;
  started failing Feb-2026. Corrected, and the two missing Tecno branch accounts&lt;br /&gt;
  (Noida IN411226T, Lucknow IN404339T) added - the code previously knew only&lt;br /&gt;
  IN404338T, which has no enterprise scope and returns nothing.&lt;br /&gt;
- Existing rows were looked up by the activation date string instead of the IMEI.&lt;br /&gt;
  serial_number is the primary key, so the lookup always missed and re-persisted a&lt;br /&gt;
  row that already existed, colliding on duplicate key on any re-pull.&lt;br /&gt;
&lt;br /&gt;
Also pulls each account independently so one dead login cannot abort the remaining&lt;br /&gt;
accounts, and fails loudly when the portal rejects a login or the report call&lt;br /&gt;
instead of proceeding into a confusing downstream error.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/itelImeiActivation/ItelImeiActivationNewService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37467</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37467</guid></item>
<item><pubDate>Mon, 31 Aug 2026 11:10:13 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37466 – Show aged Apple stock on the partner Total Investment breakdown ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Show aged Apple stock on the partner Total Investment breakdown&lt;br /&gt;
&lt;br /&gt;
Adds an &apos;Apple Stock More Than 30 Days&apos; row below &apos;Unbilled Activated Stock&apos;&lt;br /&gt;
so the reason a partner&apos;s suggested credit limit dropped is visible. Display&lt;br /&gt;
only -- the figure is not deducted from the other rows.&lt;br /&gt;
&lt;br /&gt;
Value comes from partnerStat.tmp, so it reads 0 until the cron that rebuilds&lt;br /&gt;
that file has run against the new build.&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/partner-investment.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37466</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37466</guid></item>
<item><pubDate>Mon, 31 Aug 2026 11:10:07 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37465 – Exclude aged Apple stock from investment when suggesting partner credit ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Exclude aged Apple stock from investment when suggesting partner credit limits&lt;br /&gt;
&lt;br /&gt;
Apple handsets a partner has held more than 30 days from GRN no longer count&lt;br /&gt;
toward the investment that drives the suggested limit. Applied in&lt;br /&gt;
getSuggestedAmount via getCreditableInvestment, covering the SDDIRECT,&lt;br /&gt;
hundred-percent and SIDBI branches. The aged amount is logged alongside each&lt;br /&gt;
limit change so a drop can be traced.&lt;br /&gt;
&lt;br /&gt;
Scoped to the limit calculation only -- getTotalInvestment() is untouched, so&lt;br /&gt;
checkout payment options, the investment-OK gates and partner-facing screens&lt;br /&gt;
see the same stock value as before.&lt;br /&gt;
&lt;br /&gt;
Measured on prod at time of commit: 580 units / ~3.94 Cr across 88 partners.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/PartnerLimitHelper.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37465</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37465</guid></item>
<item><pubDate>Mon, 31 Aug 2026 11:10:00 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37464 – Track aged Apple stock on partner investment; add category filter ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;Track aged Apple stock on partner investment; add category filter to stock value lookup&lt;br /&gt;
&lt;br /&gt;
selectPartnerStockValueMap now takes a nullable categoryId so the same query&lt;br /&gt;
serves both the existing Live Demo exclusion (null = all categories) and the&lt;br /&gt;
new Apple handset lookup (category 10006). Existing callers pass null and are&lt;br /&gt;
behaviourally unchanged.&lt;br /&gt;
&lt;br /&gt;
PartnerDailyInvestment carries agedAppleStockAmount, populated in both the&lt;br /&gt;
single and batch investment paths. It is JPA-@Transient, so no schema change,&lt;br /&gt;
and it still travels through the partnerStat.tmp serialization the FOFO&lt;br /&gt;
investment screen reads. Deliberately not part of getTotalInvestment() -- the&lt;br /&gt;
deduction is a credit-limit policy, so stock value is unchanged for checkout,&lt;br /&gt;
the investment-OK gates and partner-facing screens.&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/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/inventory/InventoryServiceImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/PartnerInvestmentServiceImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37464</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37464</guid></item>
<item><pubDate>Mon, 31 Aug 2026 11:09:10 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37463 – Add aged-stock constants for Apple credit-limit haircut  Apple handsets ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Add aged-stock constants for Apple credit-limit haircut&lt;br /&gt;
&lt;br /&gt;
Apple handsets held by a partner beyond AGED_STOCK_APPLE_DAYS (30) days&lt;br /&gt;
from GRN are excluded from the investment used to suggest a credit limit.&lt;/div&gt;~ /trunk/profitmandi-common/src/main/java/com/spice/profitmandi/common/model/ProfitMandiConstants.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37463</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37463</guid></item>
<item><pubDate>Mon, 31 Aug 2026 11:07:59 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37462 – Fire TagListing Solr update after commit instead of inside the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Fire TagListing Solr update after commit instead of inside the write transaction&lt;br /&gt;
&lt;br /&gt;
TagListingChangeListener used a plain @EventListener, so the async Solr rebuild&lt;br /&gt;
ran on a separate thread in a new transaction while the publishing controller&lt;br /&gt;
transaction was still open. FofoSolr.updateSingleCatalog then re-read&lt;br /&gt;
tag_listing on a connection that could not see the uncommitted rows and&lt;br /&gt;
re-indexed the pre-change price; for a catalog&apos;s first-ever listing it read&lt;br /&gt;
zero rows, took the isEmpty branch and deleted the doc from Solr.&lt;br /&gt;
&lt;br /&gt;
Switched to @TransactionalEventListener(phase = AFTER_COMMIT). All publish&lt;br /&gt;
sites (TagListingController, PriceDropController, IndentController,&lt;br /&gt;
InventoryController, ModelHotDealServiceImpl) are inside a @Transactional&lt;br /&gt;
boundary, so no event is dropped.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/event/TagListingChangeListener.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37462</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37462</guid></item>
<item><pubDate>Sat, 29 Aug 2026 16:19:05 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37461 – rbm drr dashboard new ui looks</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm drr dashboard new ui looks&lt;/div&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/model/RbmBrandPartnerCountModel.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37461</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37461</guid></item>
<item><pubDate>Sat, 29 Aug 2026 16:15:18 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37460 – rbm drr dashboard new ui looks</title><description>&lt;div&gt;&lt;strong&gt;ranu – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm drr dashboard new ui looks&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;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37460</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37460</guid></item>
<item><pubDate>Sat, 29 Aug 2026 14:31:10 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37459 – Motorola IMEI activation: secondary + tertiary in one browser session ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;Motorola IMEI activation: secondary + tertiary in one browser session&lt;br /&gt;
&lt;br /&gt;
Mirrors the oppo/realme combined jobs. MotorolaImeiActivationService drives&lt;br /&gt;
CheckMotorolaWarrantyTask, with MotorolaChallengeSolver for the challenge.&lt;br /&gt;
&lt;br /&gt;
Cadence comes from the pool query, which defers an imei for `days` after each&lt;br /&gt;
attempt (saveActivation bumps createTimestamp even when no date came back), so&lt;br /&gt;
days=2 retries everything every two days. Pending pool measured 1,534&lt;br /&gt;
(1,182 secondary + 352 tertiary); at ~10-14s/imei, 60 per invocation is about&lt;br /&gt;
12 minutes of driver time and clearing the pool inside 48h needs roughly 26&lt;br /&gt;
invocations, i.e. an OS cron entry every 90 minutes.&lt;br /&gt;
&lt;br /&gt;
Do NOT schedule it inside the oppo/realme window: each driver tree costs&lt;br /&gt;
~850MB and this box has been OOM-killed twice with tomcat the victim, so peak&lt;br /&gt;
concurrent drivers is the number that matters.&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/MotorolaChallengeSolver.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/StandAlone.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37459</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37459</guid></item>
<item><pubDate>Sat, 29 Aug 2026 13:22:56 +0530</pubDate><dc:creator>aman</dc:creator><title>Rev 37458 – LOI payment screenshot: report upload failures instead of reporting the ...</title><description>&lt;div&gt;&lt;strong&gt;aman – 6 file(s) modified&lt;/strong&gt;&lt;br/&gt;LOI payment screenshot: report upload failures instead of reporting the field as missing&lt;br /&gt;
&lt;br /&gt;
Submit validated the hidden #payment-sc-docId, but a file input keeps displaying the&lt;br /&gt;
chosen filename regardless of what happens next - so a failed /document-upload left the&lt;br /&gt;
field looking attached to the operator and missing to the validator (&quot;The following&lt;br /&gt;
fields are required: Payment screenshot&quot; on a form that was in fact filled in).&lt;br /&gt;
&lt;br /&gt;
The failure was silent three ways: doAjaxUploadRequestHandler had no error handler; the&lt;br /&gt;
global ajaxError reporter calls bootbox, which loads from cdnjs and throws if that is&lt;br /&gt;
blocked; and the confirm(&apos;Confirm file upload ?&apos;) gate returned false with no trace once&lt;br /&gt;
Chrome&apos;s &quot;prevent this page from creating additional dialogs&quot; box was ticked.&lt;br /&gt;
&lt;br /&gt;
- common.js: optional error callback on doAjaxUploadRequestHandler (additive, opts out of&lt;br /&gt;
  the generic global dialog via suppressGlobalError); uploadErrorMessage() extracts the&lt;br /&gt;
  server&apos;s real reason from the JSON body or the plain-text duplicate-request body;&lt;br /&gt;
  uploadDocument() pre-checks size/type, verifies a document_id actually came back, and&lt;br /&gt;
  reports a message naming the file - .HEIC and .webp get specific guidance;&lt;br /&gt;
  showAlert() falls back to native alert when bootbox is absent.&lt;br /&gt;
- loi-form.js: drop the confirm() gate, &apos;input&apos; -&gt; &apos;change&apos;, and clear the file input&lt;br /&gt;
  whenever the id does not land so the widget can never claim an unuploaded file. Status&lt;br /&gt;
  line under the field (Uploading... / Attached: name / Not attached). Submit now&lt;br /&gt;
  distinguishes not-picked, still-uploading and upload-failed. Same treatment for the&lt;br /&gt;
  OnboardingDocumentTable and mk_brand-fee-collection-details uploads, and the brand-fee&lt;br /&gt;
  dialog names the Attachment field instead of echoing the raw form key.&lt;br /&gt;
- loi-form.vm, pendingForm.vm: accept=&quot;...&quot; on both file inputs plus the status span.&lt;br /&gt;
- FileUploadController: reject empty files, report actual size against the actual limit,&lt;br /&gt;
  and resolveExtension() falls back to the filename when the browser sends a generic MIME&lt;br /&gt;
  type (Android file managers send application/octet-stream for ordinary JPG/PNG/PDF).&lt;br /&gt;
- AppConfig: static resource version 395 -&gt; 396 for the JS change.&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/FileUploadController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/common.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/loi-form.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/loi-form.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/pendingForm.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37458</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37458</guid></item>
<item><pubDate>Sat, 29 Aug 2026 07:49:43 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37457 – Lock the KYC state to the GSTIN on the LOI ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;Lock the KYC state to the GSTIN on the LOI&lt;br /&gt;
&lt;br /&gt;
The LOI already captures and validates a GSTIN, and the first two characters of a&lt;br /&gt;
GSTIN are its GST state code - so once the LOI exists the KYC state is a fact&lt;br /&gt;
about that number, not something to re-type. When one is present the state&lt;br /&gt;
dropdown is prefilled from it and locked; otherwise it stays a normal&lt;br /&gt;
master-backed select.&lt;br /&gt;
&lt;br /&gt;
Derived from the GSTIN rather than loi_form.gstState: that column is typed by&lt;br /&gt;
hand and holds values like &apos;UP&apos;, &apos;UTTAR PARDESH&apos; and &apos;MADHAY PARDESH&apos; which&lt;br /&gt;
resolve against nothing, and it is blank on 3 rows. Checked against prod - all&lt;br /&gt;
693 GSTINs on record are 15 characters and every one resolves through&lt;br /&gt;
statemaster.stateCode, and in all 14 rows where the two disagree the GSTIN is&lt;br /&gt;
right and the typed value is wrong or empty.&lt;br /&gt;
&lt;br /&gt;
The lock is per row, not per page: the KYC screens list many onboardings, so the&lt;br /&gt;
derived state is passed as a map keyed by onboarding id. Blank rows carry their&lt;br /&gt;
onboarding id so a new KYC entry is locked too, which is the case that matters.&lt;br /&gt;
&lt;br /&gt;
data-gst-locked keeps the row&apos;s dblclick edit toggle from re-enabling the field;&lt;br /&gt;
the value still submits because the JS reads it explicitly with .val().&lt;/div&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/PartnerOnBoardingPanelController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/panel-listing.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/fofo-kyc-row.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/legal-kyc-row.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37457</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37457</guid></item>
<item><pubDate>Sat, 29 Aug 2026 07:42:55 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37456 – Block billing when NIC rejects the transporter GSTIN for e-way ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 6 file(s) modified&lt;/strong&gt;&lt;br/&gt;Block billing when NIC rejects the transporter GSTIN for e-way bills&lt;br /&gt;
&lt;br /&gt;
NIC files the e-way bill alongside the IRN, so a deregistered transporter&lt;br /&gt;
GSTIN returns Status=1 with InfoDtls[InfCd=EWBERR] (3029 &quot;GSTIN - ... is&lt;br /&gt;
not active&quot;): the IRN is valid while ewb_no stays null. Nothing downstream&lt;br /&gt;
reads that as a failure, so invoices kept being issued for goods that&lt;br /&gt;
could not legally move.&lt;br /&gt;
&lt;br /&gt;
Cache the rejected transporter GSTIN in Redis and refuse to bill through&lt;br /&gt;
it. The block is keyed on the GSTIN, since one GSTIN is shared by several&lt;br /&gt;
warehouse_provider rows, and it carries the day it was raised so it lapses&lt;br /&gt;
at midnight and each new day re-tests NIC once. Correcting the GSTIN in&lt;br /&gt;
the provider panel lifts it immediately.&lt;br /&gt;
&lt;br /&gt;
Only errors that are the transporter&apos;s fault block billing - NIC&apos;s 3029,&lt;br /&gt;
or any message naming the GSTIN we sent as TransId. Every other EWBERR&lt;br /&gt;
behaves as before: the IRN is filed and the e-way bill is retried later.&lt;br /&gt;
&lt;br /&gt;
Guard sits in addBillingDetailsForGrouppedOrders before the pessimistic&lt;br /&gt;
lock and before any mutation, mirroring LogisticsServiceImpl#getEwbDetails&lt;br /&gt;
(order&apos;s own warehouse; self-pickup and runner skipped, as they travel on&lt;br /&gt;
a vehicle number rather than a transporter id).&lt;/div&gt;~ /trunk/profitmandi-common/src/main/java/com/spice/profitmandi/common/model/ProfitMandiConstants.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/integrations/gstpro/EwbTransporterFailureCache.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/integrations/gstpro/GstProService.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/transaction/TransactionServiceImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/test/java/com/spice/profitmandi/service/integrations/gstpro/EwbTransporterFailureCacheTest.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/provider/ProviderController.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37456</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37456</guid></item>
<item><pubDate>Sat, 29 Aug 2026 07:31:14 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37455 – Make the KYC state a master-backed dropdown instead of free ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;Make the KYC state a master-backed dropdown instead of free text&lt;br /&gt;
&lt;br /&gt;
fofo-kyc-row.vm and legal-kyc-row.vm captured state as a free-text input, so&lt;br /&gt;
nothing stopped a spelling the master does not hold. That state is resolved back&lt;br /&gt;
through inventory.statemaster by name later, and an unresolvable one cannot be&lt;br /&gt;
turned into a state code. Both now render a $stateNames select, and all five&lt;br /&gt;
render paths in PartnerOnBoardingPanelController supply the list.&lt;br /&gt;
&lt;br /&gt;
panel-listing.js reads these fields positionally, by td index and&lt;br /&gt;
input[type=&apos;text&apos;]. A select does not match that selector, so the value would&lt;br /&gt;
have come back undefined and KYC would have saved a blank state silently -&lt;br /&gt;
both selectors now target the select. Row editing is unaffected: the enable&lt;br /&gt;
toggle uses :input, which covers select.&lt;br /&gt;
&lt;br /&gt;
Bump the asset version for the panel-listing.js change.&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/PartnerOnBoardingPanelController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/panel-listing.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/fofo-kyc-row.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/legal-kyc-row.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37455</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37455</guid></item>
<item><pubDate>Sat, 29 Aug 2026 07:24:40 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37454 – Build googleMailSender as AuthenticatedIdentityMailSender  The bean authenticates as sdtech@smartdukaan.com, ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Build googleMailSender as AuthenticatedIdentityMailSender&lt;br /&gt;
&lt;br /&gt;
The bean authenticates as &lt;a href=&quot;mailto:sdtech@smartdukaan.com&quot;&gt;sdtech@smartdukaan.com&lt;/a&gt;, so Google Workspace only permits&lt;br /&gt;
that address in From. Callers hardcode noreply@, which Gmail refuses with 535&lt;br /&gt;
&apos;Authenticated user is not authorized to send mail&apos;, silently dropping every alert&lt;br /&gt;
sent through it. The sender now rewrites From to its own username at send time.&lt;br /&gt;
&lt;br /&gt;
See profitmandi-common r37451.&lt;/div&gt;~ /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/config/AppConfig.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37454</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37454</guid></item>
<item><pubDate>Sat, 29 Aug 2026 07:24:39 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37453 – Build googleMailSender as AuthenticatedIdentityMailSender  The bean authenticates as sdtech@smartdukaan.com, ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Build googleMailSender as AuthenticatedIdentityMailSender&lt;br /&gt;
&lt;br /&gt;
The bean authenticates as &lt;a href=&quot;mailto:sdtech@smartdukaan.com&quot;&gt;sdtech@smartdukaan.com&lt;/a&gt;, so Google Workspace only permits&lt;br /&gt;
that address in From. Callers hardcode noreply@, which Gmail refuses with 535&lt;br /&gt;
&apos;Authenticated user is not authorized to send mail&apos;, silently dropping every alert&lt;br /&gt;
sent through it. The sender now rewrites From to its own username at send time.&lt;br /&gt;
&lt;br /&gt;
See profitmandi-common r37451.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/Application.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37453</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37453</guid></item>
<item><pubDate>Sat, 29 Aug 2026 07:24:31 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37452 – Fix e-invoice IRN failure when the NIC auth token is ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Fix e-invoice IRN failure when the NIC auth token is about to expire&lt;br /&gt;
&lt;br /&gt;
NIC reissues the same auth token until it genuinely expires, so evicting the cache&lt;br /&gt;
inside the 5 minute leeway hands back the identical near-dead token. getAuthenticatedHeaders&lt;br /&gt;
checked the leeway once, before that re-fetch, and never inspected what came back.&lt;br /&gt;
NSUPHR1770 filed with a token that had 12 seconds of life left and the gateway answered&lt;br /&gt;
412/GSP752 &apos;eInvoice AuthToken not found or expired&apos;; the invoice filed a minute later,&lt;br /&gt;
past the expiry and so on a genuinely new token, succeeded.&lt;br /&gt;
&lt;br /&gt;
getUsableAuthToken re-checks the refetched token and, when it is still inside a 60s&lt;br /&gt;
floor, waits out the remainder before minting again. The wait is bounded by that floor&lt;br /&gt;
and every caller on this path is a cron/async thread already running against a 60s NIC&lt;br /&gt;
timeout with no transaction held open.&lt;br /&gt;
&lt;br /&gt;
Also make the gateway&apos;s own failures legible. NIC rejections arrive as&lt;br /&gt;
{Status, ErrorDetails}, but failures the ASP raises in front of NIC use&lt;br /&gt;
{status_cd, error{error_cd, message}}, which shares no field name with RespPl: Gson&lt;br /&gt;
produced an all-null object and the stored reason degraded to the literal&lt;br /&gt;
&apos;RespPl{Status=0, Data=null, ErrorDetails=null, InfoDtls=null}&apos;, indistinguishable from&lt;br /&gt;
NIC rejecting the document. RespGSPErr already modelled that envelope but was a&lt;br /&gt;
non-static inner class and so could not be instantiated by Gson; made it static and&lt;br /&gt;
copy the code and message into ErrorDetails, which every caller already reads.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/integrations/gstpro/api/model/E_InvoiceCommon.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/service/integrations/gstpro/GstProAuthService.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37452</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37452</guid></item>
<item><pubDate>Sat, 29 Aug 2026 07:24:19 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37451 – Send authenticated mail as the account that actually authenticates  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Send authenticated mail as the account that actually authenticates&lt;br /&gt;
&lt;br /&gt;
googleMailSender logs in to smtp.gmail.com as &lt;a href=&quot;mailto:sdtech@smartdukaan.com&quot;&gt;sdtech@smartdukaan.com&lt;/a&gt;, but callers&lt;br /&gt;
build their From as &lt;a href=&quot;mailto:noreply@smartdukaan.com&quot;&gt;noreply@smartdukaan.com&lt;/a&gt;. Google Workspace binds an authenticated&lt;br /&gt;
session to one identity and refuses the mismatch with 535 &apos;Authorization failed:&lt;br /&gt;
Authenticated user is not authorized to send mail&apos; - the password is accepted, the&lt;br /&gt;
message is not. Every alert routed through that sender was therefore lost at the SMTP&lt;br /&gt;
layer, the e-invoice failure alert for NSUPHR1770 among them.&lt;br /&gt;
&lt;br /&gt;
AuthenticatedIdentityMailSender rewrites From to the sender&apos;s own username at send&lt;br /&gt;
time, keeping whatever display name the caller chose. Senders that do not authenticate&lt;br /&gt;
are left alone: gmailRelaySender is the IP-authorised relay and has no username, and&lt;br /&gt;
sendGridMailSender&apos;s username is the literal &apos;apikey&apos;, so both keep noreply@.&lt;br /&gt;
&lt;br /&gt;
Enforced in the sender rather than at the ~40 call sites that build their own&lt;br /&gt;
MimeMessage and hardcode noreply@, so it covers the ones added next too.&lt;/div&gt;+ /trunk/profitmandi-common/src/main/java/com/spice/profitmandi/common/services/AuthenticatedIdentityMailSender.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37451</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37451</guid></item>
<item><pubDate>Sat, 29 Aug 2026 07:17:00 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37450 – Oppo: find only the hole, and let a low-contrast hole ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Oppo: find only the hole, and let a low-contrast hole be found at all&lt;br /&gt;
&lt;br /&gt;
60% of oppo attempts never got past detection -- getMatCircles2 returned null and&lt;br /&gt;
the attempt was wasted before any aiming happened. That is a bigger loss than&lt;br /&gt;
everything the scheduling work addressed put together.&lt;br /&gt;
&lt;br /&gt;
Two causes, both visible once real puzzles are captured and looked at.&lt;br /&gt;
&lt;br /&gt;
1. param1 is the Canny HIGH threshold, and it was 100. Edges weaker than that are&lt;br /&gt;
   discarded before circle finding begins. Measured hole-vs-background contrast on&lt;br /&gt;
   four live puzzles: 98, 103, 28, 117. The 28 -- a pale lilac background -- cannot&lt;br /&gt;
   produce an edge at 100, so no circle exists to find. Dropped to 50.&lt;br /&gt;
&lt;br /&gt;
2. It insisted on TWO circles whose radii matched within 3px, and returned null&lt;br /&gt;
   otherwise. So a puzzle where the hole was located perfectly still failed if the&lt;br /&gt;
   ring was missed, or if the two radii differed by 4px.&lt;br /&gt;
&lt;br /&gt;
The second is the sillier one: the ring is a DOM element,&lt;br /&gt;
dx_captcha_basic_sub-slider_, whose exact position aim() already reads via&lt;br /&gt;
pieceCentreX(). Detection was re-finding something known exactly, and then&lt;br /&gt;
throwing away a good hole because it could not confirm it. Now the ring position&lt;br /&gt;
is passed in and hough only has to find one thing.&lt;br /&gt;
&lt;br /&gt;
Lowering param1 without the pairing check would let textured backgrounds (the&lt;br /&gt;
sand images especially) supply spurious circles with nothing to reject them, so&lt;br /&gt;
the candidate is verified as an actual hole: its core must be at least 15&lt;br /&gt;
luminance below the frame mean. Real holes measure 28-117 below, so 15 rejects&lt;br /&gt;
noise with margin.&lt;br /&gt;
&lt;br /&gt;
Validated against live puzzles before committing:&lt;br /&gt;
  ring is at rel 42px on every sample; hole lands at 113-194px, separation&lt;br /&gt;
  71-152px -- so RING_EXCLUSION_PX = 30 never rejects a real hole&lt;br /&gt;
  hole contrast 28-117 against MIN_HOLE_DARKNESS = 15&lt;br /&gt;
&lt;br /&gt;
Not validated locally: the hough call itself. opencv 3.4.2-0 ships no osx/arm64&lt;br /&gt;
native and every JDK on this machine is arm64, so the detection path cannot run&lt;br /&gt;
here. param1 = 50 is reasoned from the measured contrasts, not measured. If the&lt;br /&gt;
detection rate does not move, 40 is the next value to try -- the darkness check is&lt;br /&gt;
what makes going lower safe.&lt;br /&gt;
&lt;br /&gt;
Watch &quot;Detected N circle(s) but all sat on the ring&quot; and &quot;Rejecting circle at Npx&quot;&lt;br /&gt;
in the log: the first means hough found nothing but the ring, the second means the&lt;br /&gt;
darkness check is doing its job.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/CheckOppoWarrantyTask.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37450</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37450</guid></item>
<item><pubDate>Fri, 28 Aug 2026 20:25:12 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37449 – Realme unmerged too: four selenium jobs, one per pool per ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Realme unmerged too: four selenium jobs, one per pool per brand&lt;br /&gt;
&lt;br /&gt;
r37447 merged secondary and tertiary per brand to halve concurrent drivers.&lt;br /&gt;
r37448 reverted that for oppo, because serialising cost it more per imei than a&lt;br /&gt;
second browser did. This reverts it for realme as well, which ends the merge&lt;br /&gt;
experiment entirely.&lt;br /&gt;
&lt;br /&gt;
What the merge actually cost realme is only visible now that oppo is parallel&lt;br /&gt;
again: realme&apos;s per-imei went 14.2s -&gt; 29s. It did not change behaviour -- it is&lt;br /&gt;
simply competing with oppo&apos;s two browsers for CPU. At 29s its merged ceiling is&lt;br /&gt;
86400/29 = 2,979/day, just under the 3,054/day the daily re-check needs, so no&lt;br /&gt;
batch size could have closed the gap. Two parallel pools restore the ~3,900/day&lt;br /&gt;
it managed historically at four drivers.&lt;br /&gt;
&lt;br /&gt;
Measured before this change (25 min window):&lt;br /&gt;
&lt;br /&gt;
  brand    needed/day   throughput   note&lt;br /&gt;
  Oppo         8,838       7,661     parallel revert worked, +122%&lt;br /&gt;
  Realme       3,054       1,843     merged and CPU-starved&lt;br /&gt;
  Vivo        10,082      16,128     surplus, cannot transfer to another brand&lt;br /&gt;
&lt;br /&gt;
Sizes unchanged: oppo 25 per pool, realme 12 per pool, vivo 50+10.&lt;br /&gt;
&lt;br /&gt;
Honest accounting of the merge: it was my idea, sized on per-brand arithmetic that&lt;br /&gt;
ignored contention between brands, and it is now fully reverted. What survives&lt;br /&gt;
from that line of work is the part that actually paid -- reaping orphaned browsers&lt;br /&gt;
(~1.8GB), the per-brand retry caps, and per-brand maxResults. Peak drivers are&lt;br /&gt;
back to 4, which is where they started.&lt;br /&gt;
&lt;br /&gt;
Watch for contention: four browsers is the configuration that produced the 29s&lt;br /&gt;
figure for realme in the first place, so oppo may slow from its current 19.7s.&lt;br /&gt;
Re-measure both before tuning sizes again.&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=37449</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37449</guid></item>
<item><pubDate>Fri, 28 Aug 2026 12:08:39 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37448 – Daily re-check for all brands; Oppo back to parallel pools ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;Daily re-check for all brands; Oppo back to parallel pools&lt;br /&gt;
&lt;br /&gt;
Two changes.&lt;br /&gt;
&lt;br /&gt;
1. Re-check window 4 days (secondary) and 2 days (tertiary) -&gt; 1 day everywhere.&lt;br /&gt;
   Daily demand becomes the full universe rather than a fraction of it:&lt;br /&gt;
&lt;br /&gt;
     Oppo    4,798 + 4,040 =  8,838/day&lt;br /&gt;
     Vivo    9,407 +   675 = 10,082/day   (doing 15,345 -- fine)&lt;br /&gt;
     Realme  1,973 + 1,081 =  3,054/day&lt;br /&gt;
&lt;br /&gt;
2. Oppo&apos;s two pools run in PARALLEL again, reverting the merge in r37447 for that&lt;br /&gt;
   brand only. Realme stays merged.&lt;br /&gt;
&lt;br /&gt;
   The merge was a straight trade of throughput for memory and oppo could not&lt;br /&gt;
   afford it. Measured over 32 minutes and again over an hour the next morning:&lt;br /&gt;
   3,555 then 3,456/day against 5,280 before merging. Batch cadence settled at a&lt;br /&gt;
   very regular ~15.5 min per cycle, so a 30-imei merged batch takes ~10.5 min =&lt;br /&gt;
   ~21s/imei, against the 10.2s it managed unmerged. At 21s the ceiling is&lt;br /&gt;
   86400/21 = 4,114/day even with zero idle, so no batch size and no shorter&lt;br /&gt;
   fixedDelay could have reached 8,838. Serialising simply costs more per imei&lt;br /&gt;
   here than running two browsers does.&lt;br /&gt;
&lt;br /&gt;
   Realme keeps the merge: it needs 3,054/day and delivers 2,952 merged, so a&lt;br /&gt;
   small size bump covers it without a second browser.&lt;br /&gt;
&lt;br /&gt;
Sizes: oppo 25 per pool (2 jobs in parallel), realme 12+12 merged, vivo 50+10&lt;br /&gt;
unchanged. Vivo has already cleared its entire secondary backlog -- the pool&lt;br /&gt;
reads 0 and both lists come back empty -- which is what the batch of 50 was for.&lt;br /&gt;
&lt;br /&gt;
Cost: oppo goes back to two concurrent drivers, so the fleet is 3 rather than 2,&lt;br /&gt;
roughly +700MB. Acceptable against the ~2GB freed today by reaping orphaned&lt;br /&gt;
browsers and capping retries, but it is the reason realme was left merged.&lt;br /&gt;
&lt;br /&gt;
Sizes are a starting point, not a final answer: oppo&apos;s per-imei time differs&lt;br /&gt;
markedly between merged and parallel modes, so re-measure before tuning further.&lt;/div&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=37448</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37448</guid></item>
<item><pubDate>Thu, 27 Aug 2026 20:36:36 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37447 – Selenium: one browser per brand instead of one per pool ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Selenium: one browser per brand instead of one per pool&lt;br /&gt;
&lt;br /&gt;
Oppo and Realme each ran secondary and tertiary as separate @Scheduled jobs, so&lt;br /&gt;
each brand opened two ChromeDrivers at once and the fleet ran four. Each driver&lt;br /&gt;
tree costs roughly 850MB. This box co-hosts a 9.4GB tomcat with ~3GB available&lt;br /&gt;
and has been OOM-killed twice this month -- tomcat was the victim both times, so&lt;br /&gt;
peak concurrency is the thing that matters here.&lt;br /&gt;
&lt;br /&gt;
Combined into one job per brand. Nothing downstream changes: the two pools differ&lt;br /&gt;
only in which named query fills them, and both already funnel into the same&lt;br /&gt;
updateActivationDate -&gt; checkWarranty -&gt; saveActivation path. They are disjoint by&lt;br /&gt;
construction (secondary excludes anything with a FofoLineItem, tertiary is&lt;br /&gt;
FofoLineItem-based); distinct() is insurance, not a fix for a known overlap.&lt;br /&gt;
&lt;br /&gt;
Sizing matters, because merging SERIALISES work that used to run in parallel and&lt;br /&gt;
keeping the old batch sizes would quietly cost throughput. Measured post-cap at&lt;br /&gt;
10.2s/imei (oppo, down from 14.6 after r37445) and 14.2s/imei (realme), solving&lt;br /&gt;
M * 86400 / (300 + M*t):&lt;br /&gt;
&lt;br /&gt;
  oppo    2 parallel jobs x10 = 4,299/day  -&gt;  merged 15+15 = 4,277/day  (parity)&lt;br /&gt;
  realme  2 parallel jobs x10 = 3,910/day  -&gt;  merged 10+10 = 2,959/day  (-24%)&lt;br /&gt;
&lt;br /&gt;
Oppo is sized to hold parity because it is already short of its 4,798/day need.&lt;br /&gt;
Realme is left at 20 -- it needs 2,243/day, so it can absorb the dip in exchange&lt;br /&gt;
for shorter batches and a shorter-lived browser.&lt;br /&gt;
&lt;br /&gt;
What this saves and does not save: total driver-SECONDS are roughly unchanged,&lt;br /&gt;
which is the point of resizing. PEAK concurrent drivers halves from 4 to 2.&lt;br /&gt;
&lt;br /&gt;
Also skips starting a browser at all when both pools come back empty -- currently&lt;br /&gt;
never true, but it costs nothing and a browser launched to do nothing is pure&lt;br /&gt;
waste on this box.&lt;br /&gt;
&lt;br /&gt;
checkOppoImeiStatus/Tertiary and the realme equivalents are left in place for&lt;br /&gt;
manual invocation; they are simply no longer scheduled.&lt;/div&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;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37447</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37447</guid></item>
<item><pubDate>Thu, 27 Aug 2026 20:27:13 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37446 – Per-brand batch sizes, and stop chrome forking a GPU process ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 6 file(s) modified&lt;/strong&gt;&lt;br/&gt;Per-brand batch sizes, and stop chrome forking a GPU process it cannot use&lt;br /&gt;
&lt;br /&gt;
maxResults was hardcoded in the shared repository methods, so Oppo and Vivo were&lt;br /&gt;
forced to the same secondary batch (10) and all three to the same tertiary (10).&lt;br /&gt;
It is now a parameter, set per brand at the call site.&lt;br /&gt;
&lt;br /&gt;
Sizing is arithmetic, from measured IN-BATCH per-imei time. Solving&lt;br /&gt;
M * 86400 / (300 + M*t) = needed/day:&lt;br /&gt;
&lt;br /&gt;
  brand    needed/day   t       M required   set to&lt;br /&gt;
  Vivo         9,407    0.8s        36         50    clears, ~12,700/day&lt;br /&gt;
  Realme       1,973   13.4s        10         10    was 5 = ~1,177/day, short&lt;br /&gt;
  Oppo         4,798   14.6s        88         10    HELD, see below&lt;br /&gt;
&lt;br /&gt;
Correcting an earlier measurement of mine: I reported Vivo at 13.6s per imei and&lt;br /&gt;
concluded its backlog could not be cleared. That averaged across the ~300s idle&lt;br /&gt;
gaps BETWEEN batches. In-batch it is 0.8s -- Vivo is 17x faster than I said, is&lt;br /&gt;
idle ~97% of the time, and 50 clears its pool comfortably. There is no wait in&lt;br /&gt;
the Vivo path; it is simply fast.&lt;br /&gt;
&lt;br /&gt;
Oppo is deliberately NOT raised. At 14.6s it would need M=88, which means&lt;br /&gt;
20-minute batches and near-permanent chrome sessions. But that 14.6s predates the&lt;br /&gt;
retry cap (r37445), which cuts exhausted imeis from 20 attempts to 7 and should&lt;br /&gt;
drop it sharply. Re-measure before sizing Oppo, rather than guessing high on a&lt;br /&gt;
box with 3GB free.&lt;br /&gt;
&lt;br /&gt;
Also: --disable-gpu, --disable-dev-shm-usage, --disable-software-rasterizer on&lt;br /&gt;
both selenium tasks. Headless needs no GPU yet chrome forks a gpu-process per&lt;br /&gt;
browser -- 6 were alive across the fleet, pure overhead. No behaviour change.&lt;br /&gt;
&lt;br /&gt;
Batch size does not raise peak concurrency (fixedDelay means one batch per job at&lt;br /&gt;
a time, so never more than 4 drivers). It raises DUTY CYCLE, which converts&lt;br /&gt;
chrome&apos;s footprint from intermittent to sustained. That matters here: tomcat is&lt;br /&gt;
9.4GB, available is ~3GB, and the two OOM kills this month both took tomcat.&lt;br /&gt;
&lt;br /&gt;
Cron-only deploy. The dao signature change has no callers outside cron.&lt;/div&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;~ /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;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/ActivatedImeiRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/fofo/ActivatedImeiRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37446</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37446</guid></item>
<item><pubDate>Thu, 27 Aug 2026 18:47:45 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37445 – Oppo/Realme: cap captcha retries per tick at 7 and 12, ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Oppo/Realme: cap captcha retries per tick at 7 and 12, measured per brand&lt;br /&gt;
&lt;br /&gt;
Most captcha work goes to imeis that never succeed. Measured over the last&lt;br /&gt;
window: oppo 6,245 attempts for 308 successes, realme 13,842 for 399. The bulk&lt;br /&gt;
is imeis grinding all 20 attempts in one already-refused session and getting&lt;br /&gt;
nothing -- oppo 279 of them, realme 610.&lt;br /&gt;
&lt;br /&gt;
The imei is NOT abandoned. A captcha failure is a technical failure, not an&lt;br /&gt;
answer, so it stays pending and the next tick retries it in ~5 minutes with a&lt;br /&gt;
fresh page and session -- which the data suggests beats continuing in a session&lt;br /&gt;
the widget has refused seven times. This caps grinding, not retrying.&lt;br /&gt;
&lt;br /&gt;
Per-brand caps, because the distributions genuinely differ:&lt;br /&gt;
&lt;br /&gt;
  OPPO cap 7    97.7% of successes kept, 58.4% of work saved (3,648 attempts)&lt;br /&gt;
    Pre-glide, 33% of oppo&apos;s successes came from attempts 8-20 and 20 was the&lt;br /&gt;
    right number. Post-glide (r37440) that is 2%: the drag lands first or second&lt;br /&gt;
    try. cap 5 keeps 95.5%/saves 67.7%, cap 10 keeps 99.0%/saves 44.8%.&lt;br /&gt;
&lt;br /&gt;
  REALME cap 12  96.0% kept, 35.7% saved (4,937 attempts)&lt;br /&gt;
    NOT 7. Realme has no glide, so its successes still spread to attempt 10+ and&lt;br /&gt;
    a cap of 7 would cost it 16.5%. It also burns more than twice oppo&apos;s work, so&lt;br /&gt;
    the gentler cap still saves more in absolute terms.&lt;br /&gt;
&lt;br /&gt;
Combined: 8,585 of 20,087 attempts saved, ~43% less browser work, for ~3% fewer&lt;br /&gt;
successes per tick -- and those imeis come back next tick anyway. Less Chrome&lt;br /&gt;
work matters on this box: it co-hosts a 9.4GB tomcat, has 3.5GB free and has been&lt;br /&gt;
OOM-killed twice this month.&lt;br /&gt;
&lt;br /&gt;
The two caps are independent constants and must not be synced. If glide is ported&lt;br /&gt;
to realme, expect its curve to shift left as oppo&apos;s did and its cap can drop to&lt;br /&gt;
~7 -- but measure it, do not assume it.&lt;br /&gt;
&lt;br /&gt;
Windows are ~2h (oppo&apos;s only ~30 min post-glide), so the right numbers may drift.&lt;br /&gt;
Worth re-reading the attempt histogram after a full day.&lt;/div&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=37445</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37445</guid></item>
<item><pubDate>Thu, 27 Aug 2026 17:36:31 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37444 – rbm drr dashboard new ui looks</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm drr dashboard new ui looks&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=37444</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37444</guid></item>
<item><pubDate>Thu, 27 Aug 2026 17:33:30 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37443 – rbm drr dashboard new ui looks</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm drr dashboard new ui looks&lt;/div&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/model/RbmBrandSoldModel.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37443</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37443</guid></item>
<item><pubDate>Thu, 27 Aug 2026 17:28:05 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37442 – rbm drr dashboard new ui looks</title><description>&lt;div&gt;&lt;strong&gt;ranu – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;rbm drr dashboard new ui looks&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-today-arr.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/today_po_rbm.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37442</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37442</guid></item>
<item><pubDate>Thu, 27 Aug 2026 17:02:33 +0530</pubDate><dc:creator>ranu</dc:creator><title>Rev 37441 – bi access to gaurav mathur</title><description>&lt;div&gt;&lt;strong&gt;ranu – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;bi access to gaurav mathur&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/ScheduledTasksTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37441</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37441</guid></item>
<item><pubDate>Thu, 27 Aug 2026 13:27:35 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37440 – Oppo: slide the drag in eased sub-moves instead of jumping ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Oppo: slide the drag in eased sub-moves instead of jumping&lt;br /&gt;
&lt;br /&gt;
Aim is solved and it did not finish the job: r37438 lands the ring 0-1px from the&lt;br /&gt;
hole on 103 of 104 drags and oppo still converts ~15%, with POSITION_MISMATCH on&lt;br /&gt;
the rest. So the widget is refusing drags that end in the right place.&lt;br /&gt;
&lt;br /&gt;
Dingxiang scores trajectory and velocity as well as final position and returns the&lt;br /&gt;
same POSITION_MISMATCH for both, so our verdict cannot separate &quot;wrong place&quot; from&lt;br /&gt;
&quot;wrong-looking movement&quot;. The circumstantial case for the latter:&lt;br /&gt;
&lt;br /&gt;
  oppo    0.91s hold, 2-3 discrete jumps   -&gt; 15%&lt;br /&gt;
  realme  1.93s hold, slower and more      -&gt; 54-74%&lt;br /&gt;
&lt;br /&gt;
and r37438 made oppo FASTER by removing the per-step screenshots, moving it further&lt;br /&gt;
from realme&apos;s profile rather than closer.&lt;br /&gt;
&lt;br /&gt;
glide() traverses each leg as up to 18 small sub-moves on an ease-out curve&lt;br /&gt;
(1-(1-t)^2, quick then settling) with a 45ms pause between, so the pointer&lt;br /&gt;
describes a continuous decelerating path instead of teleporting.&lt;br /&gt;
&lt;br /&gt;
Nothing about the DISTANCE changes -- it is still exactly what the derived ratio&lt;br /&gt;
says, and verified to land on it precisely: a 116px leg becomes&lt;br /&gt;
[16,15,13,13,11,10,9,8,6,6,4,3,1,1] and sums to 116. Negative legs work the same&lt;br /&gt;
way for overshoot correction.&lt;br /&gt;
&lt;br /&gt;
To be explicit, since this is the thing not to get wrong: the ratio remains fully&lt;br /&gt;
derived. It starts at zero and comes only from measured movement, per attempt and&lt;br /&gt;
per step. Splitting a leg into sub-moves gives MORE measured legs, not fewer, so&lt;br /&gt;
the estimate sharpens rather than being replaced by an assumption. No constant is&lt;br /&gt;
introduced -- MAX_GLIDE_STEPS, GLIDE_PX_PER_STEP and GLIDE_PAUSE_MS describe the&lt;br /&gt;
path, not the relationship between mouse px and ring px.&lt;br /&gt;
&lt;br /&gt;
Expected hold ~1.7s against realme&apos;s 1.93s. Oppo only.&lt;br /&gt;
&lt;br /&gt;
This is a hypothesis test, not a known fix. POSITION_MISMATCH rate answers it in&lt;br /&gt;
one tick; if it does not move, drag dynamics is eliminated and the remaining&lt;br /&gt;
suspect is Hough picking the wrong circle pair on oppo&apos;s imagery, which needs&lt;br /&gt;
visual evidence rather than another code change.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/CheckOppoWarrantyTask.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37440</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37440</guid></item>
<item><pubDate>Thu, 27 Aug 2026 13:12:09 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37439 – Oppo: drop the stale nudgeFor javadoc that still referenced ASSUMED_RATIO ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Oppo: drop the stale nudgeFor javadoc that still referenced ASSUMED_RATIO&lt;br /&gt;
&lt;br /&gt;
Comment only, no code change.&lt;br /&gt;
&lt;br /&gt;
nudgeFor() and ASSUMED_RATIO were removed in r37438, but the javadoc describing&lt;br /&gt;
them was left orphaned above ALIGNED_PX, still explaining how to size a probe from&lt;br /&gt;
an assumed px-per-px. That is precisely the thing not to reintroduce, and a stale&lt;br /&gt;
comment arguing for it is an invitation to do so.&lt;br /&gt;
&lt;br /&gt;
Replaced with a note on why there is no assumed ratio: it is derived from real&lt;br /&gt;
movement on every attempt and re-derived on every step within it. The constant was&lt;br /&gt;
tuned twice (1.7 -&gt; 0.67 -&gt; 1.7) against measurements contaminated by the leaked&lt;br /&gt;
slider press, and never helped. The widget&apos;s px-per-px genuinely varies by&lt;br /&gt;
environment (1.4-1.5 in production, 1.1-1.2 locally) and by brand, which is the&lt;br /&gt;
reason it has to be measured rather than assumed.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/CheckOppoWarrantyTask.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37439</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37439</guid></item>
<item><pubDate>Thu, 27 Aug 2026 06:38:15 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37438 – Oppo: aim by tracking the ring element, not by re-detecting ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Oppo: aim by tracking the ring element, not by re-detecting circles&lt;br /&gt;
&lt;br /&gt;
r37437&apos;s closed loop could not close. Production, 13 minutes:&lt;br /&gt;
&lt;br /&gt;
  step 0 (probe) ok    36&lt;br /&gt;
  lost the circles     32   (25 of them on step 1, right after the main move)&lt;br /&gt;
  aligned within 2px    0&lt;br /&gt;
&lt;br /&gt;
The probe worked and derived sane ratios (0.75-1.00), then the next measurement&lt;br /&gt;
returned null nearly every time and the loop bailed.&lt;br /&gt;
&lt;br /&gt;
The cause is structural, not a tuning miss. getMatCircles2 needs Hough to resolve&lt;br /&gt;
TWO circles of similar radius, and as the ring closes on the hole they overlap and&lt;br /&gt;
stop being two. The measurement dies exactly at convergence, so no loop built on&lt;br /&gt;
&quot;distance between two detected circles&quot; can ever verify success. The old refine()&lt;br /&gt;
hit the same wall and silently released, which is why it never helped either.&lt;br /&gt;
&lt;br /&gt;
So detection is now used ONCE, for what it is good at -- locating the hole while&lt;br /&gt;
the two are still far apart -- and from then on we track the ring&apos;s OWN element,&lt;br /&gt;
dx_captcha_basic_sub-slider_, whose rect stays readable however close it gets.&lt;br /&gt;
&lt;br /&gt;
Validated on the live widget before committing:&lt;br /&gt;
&lt;br /&gt;
  bg element    page x=556, width 288 CSS&lt;br /&gt;
  ring centre   page 598  -&gt;  42 relative to bg&lt;br /&gt;
  dark target   138 relative to bg  -&gt;  page 694, gap 96px&lt;br /&gt;
&lt;br /&gt;
The ring sits in the same 0-288 CSS space as OpenCV&apos;s x values, so bg.x + circleX&lt;br /&gt;
is directly comparable to the ring&apos;s position. That holds because getMatCircles2&lt;br /&gt;
crops by CSS coordinates and chrome runs --force-device-scale-factor=1. A 96px gap&lt;br /&gt;
matches the range production logs as &quot;Distance is&quot;.&lt;br /&gt;
&lt;br /&gt;
Also validated earlier that the ring&apos;s rect tracks a drag cleanly the whole way in&lt;br /&gt;
(+10 mouse -&gt; +11 ring, repeatably), which is the property the circle detection&lt;br /&gt;
lacks.&lt;br /&gt;
&lt;br /&gt;
The ratio is still derived per move and is now signed, so overshoot corrects itself&lt;br /&gt;
rather than needing to be detected. No screenshot or Hough pass per step either, so&lt;br /&gt;
the drag is quicker as well.&lt;br /&gt;
&lt;br /&gt;
Oppo only. Realme is converting 78% and is not touched.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/CheckOppoWarrantyTask.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37438</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37438</guid></item>
<item><pubDate>Thu, 27 Aug 2026 06:25:11 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37437 – Oppo: derive the drag ratio from every move, and survive ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Oppo: derive the drag ratio from every move, and survive a stale slider&lt;br /&gt;
&lt;br /&gt;
Two changes, both oppo only. Realme is converting 82% and is left alone.&lt;br /&gt;
&lt;br /&gt;
1. No assumed ratio -- aim() is a closed loop.&lt;br /&gt;
&lt;br /&gt;
   ASSUMED_RATIO only ever sized the FIRST probe, but the old path then derived&lt;br /&gt;
   px-per-px once from that single probe and trusted it for the main move and the&lt;br /&gt;
   correction alike. refine() re-measured the gap but reused the same ratio and&lt;br /&gt;
   never checked whether its own correction landed, so one noisy probe poisoned&lt;br /&gt;
   everything after it.&lt;br /&gt;
&lt;br /&gt;
   aim() seeds with a small fixed 12px nudge -- small enough that it cannot cross&lt;br /&gt;
   the hole -- then re-derives the ratio from what each move actually achieved and&lt;br /&gt;
   blends it with the running estimate. Up to 5 steps, stopping as soon as the gap&lt;br /&gt;
   is within ALIGNED_PX.&lt;br /&gt;
&lt;br /&gt;
   It can also see overshoot, which a single pass cannot: the gap is |c1 - c2| and&lt;br /&gt;
   cannot tell &quot;not there yet&quot; from &quot;gone past&quot;, but if a move makes the gap GROW&lt;br /&gt;
   we have crossed the hole, and the next step flips sign.&lt;br /&gt;
&lt;br /&gt;
   This removes the constant rather than retuning it, so it is immune to the scale&lt;br /&gt;
   differences we measured between environments -- 1.1-1.2 px per px locally&lt;br /&gt;
   against 0.67-0.86 in production. Supersedes r37433 and r37436 for oppo.&lt;br /&gt;
   calibrate(), refine() and nudgeFor() are now dead and removed.&lt;br /&gt;
&lt;br /&gt;
2. Re-find the slider when it goes stale instead of dropping the imei.&lt;br /&gt;
&lt;br /&gt;
   54 of 284 oppo presses (19%) died on StaleElementReferenceException, against 0&lt;br /&gt;
   of 90 on realme -- the first asymmetry found between the two. Every one aborted&lt;br /&gt;
   the attempt and forced a full page reload.&lt;br /&gt;
&lt;br /&gt;
   The logs place it exactly: &quot;Margin Left before-&quot; succeeds, then the catch fires,&lt;br /&gt;
   so the handle goes stale between that read and moveToElement. It happens on&lt;br /&gt;
   retry iterations (before- 4px, 1px), right after the doubleClick refresh swaps&lt;br /&gt;
   the widget DOM -- the element found at the top of the attempt is already&lt;br /&gt;
   detached by the time we act on it.&lt;br /&gt;
&lt;br /&gt;
   Now re-finds and retries once. The margin-left reads are also wrapped: they are&lt;br /&gt;
   diagnostics and must never be the reason an attempt is abandoned.&lt;br /&gt;
&lt;br /&gt;
Neither change is verified in production yet. The stale fix is the one with a&lt;br /&gt;
measured asymmetry behind it; aim() is a design fix for a mechanism that was&lt;br /&gt;
provably fragile, not a fix for a measured cause of oppo&apos;s 13%.&lt;/div&gt;~ /trunk/profitmandi-cron/src/main/java/com/smartdukaan/cron/scheduled/CheckOppoWarrantyTask.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37437</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F&amp;isdir=1&amp;rev=37437</guid></item>
</channel></rss>