<?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; //trunk/profitmandi-fofo/src/main/webapp/resources/js/offer-circular-review.js</title><description>WebSVN RSS feed &#x2013; SmartDukaan</description><lastBuildDate>Thu, 08 Oct 2026 17:11:16 +0530</lastBuildDate><generator>WebSVN 2.8.6-DEV</generator><language>en</language><link>https://svn.smartdukaan.com/log.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;max=40&amp;</link><atom:link href="https://svn.smartdukaan.com/rss.php?path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;repname=SmartDukaan" rel="self" type="application/rss+xml" />
<item><pubDate>Thu, 03 Sep 2026 17:44:48 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37526 – offer circular: scope config screen, resolve screen, web offer sync ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 17 file(s) modified&lt;/strong&gt;&lt;br/&gt;offer circular: scope config screen, resolve screen, web offer sync (fofo)&lt;br /&gt;
&lt;br /&gt;
Screens (each its own endpoint, under the OFFER CIRCULAR menu):&lt;br /&gt;
- /offerCircularScope - add/edit divisions, take a brand in or out of scope,&lt;br /&gt;
  register label aliases. &apos;Remove&apos; is in_scope=0 + a required reason, never a&lt;br /&gt;
  DELETE: offer.division_id is an FK and the history would go with it.&lt;br /&gt;
- /offerCircularResolve - the product queue, split out of the review screen. The&lt;br /&gt;
  editor was a &amp;lt;td colspan=6&gt; pretending to be a form, which is why it never&lt;br /&gt;
  aligned; it is now master-detail. Naming and Coverage are separate tabs because&lt;br /&gt;
  an alias cannot answer a bundle at all - the coverage panel says so and offers&lt;br /&gt;
  the two answers that ARE safe (ignore, or reclassify as naming).&lt;br /&gt;
&lt;br /&gt;
Ingest:&lt;br /&gt;
- ScopeConfig resolves division aliases and carries the canonical label on&lt;br /&gt;
  Decision. insertOffer and ProductAliases.find use it; offer_raw_row keeps the&lt;br /&gt;
  verbatim label, being the source of truth for re-parsing.&lt;br /&gt;
- CircularIngestRunner publishes to dtr.web_offer after the document is marked&lt;br /&gt;
  PUBLISHED, in its own transaction with exceptions swallowed - a circular that&lt;br /&gt;
  parsed correctly must stay published even if the web sync fails.&lt;br /&gt;
&lt;br /&gt;
Review screen:&lt;br /&gt;
- the ingest summary was a raw Map.toString() inside a nowrap span and ran off&lt;br /&gt;
  the card; now parsed into chips with the drop reasons behind a disclosure.&lt;br /&gt;
&lt;br /&gt;
jsVersion -&gt; 417 (merged with r37525&apos;s 412; cssVersion 53 kept from that commit).&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/OfferCircularController.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/OfferCircularScopeController.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CircularIngestRunner.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CircularIngestService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/ScopeConfig.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/WebOfferSyncService.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/webapp/resources/js/offer-circular-resolve.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/offer-circular-review.js&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/webapp/resources/js/offer-circular-scope.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/admin.vm&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/offer-circular-resolve.vm&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/offer-circular-review.vm&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/offer-circular-scope.vm&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/ScopeConfigTest.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/WebOfferSyncServiceTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;rev=37526</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;rev=37526</guid></item>
<item><pubDate>Tue, 18 Aug 2026 13:37:58 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37337 – Move offer-circular ingest out of cron and into the portal ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 23 file(s) modified&lt;/strong&gt;&lt;br/&gt;Move offer-circular ingest out of cron and into the portal&lt;br /&gt;
&lt;br /&gt;
The parse now runs in profitmandi-fofo, on a background thread, triggered by the&lt;br /&gt;
upload that produced the document.&lt;br /&gt;
&lt;br /&gt;
Why: splitting one feature across two artifacts with independent deploy cadences&lt;br /&gt;
cost a full day. fofo shipped, cron did not, and a valid upload sat in DRAFT with&lt;br /&gt;
nothing on the server able to parse it - the deployed cron jar contained none of the&lt;br /&gt;
ingest classes. One 9-page PDF a month never justified a batch tier, and the portal&lt;br /&gt;
already ships two PDF stacks, so the isolation argument for keeping PDFBox out was&lt;br /&gt;
weaker than it looked.&lt;br /&gt;
&lt;br /&gt;
- 13 parser classes move verbatim from com.smartdukaan.cron.offercircular to&lt;br /&gt;
  com.spice.profitmandi.web.offercircular. No logic changed.&lt;br /&gt;
- CircularIngestScheduler becomes CircularIngestRunner: the @Scheduled(every 5 min)&lt;br /&gt;
  entry point and the offer.circular.ingest.enabled flag are gone, replaced by a&lt;br /&gt;
  single-threaded daemon executor. All claim, ingest and notification logic is&lt;br /&gt;
  unchanged.&lt;br /&gt;
- Upload hands the document id to the runner AFTER COMMIT, not inline. The DRAFT row&lt;br /&gt;
  is written inside the request transaction; a worker starting immediately would race&lt;br /&gt;
  that commit, find nothing to claim and silently do nothing - which is precisely the&lt;br /&gt;
  stuck-on-DRAFT symptom this change removes.&lt;br /&gt;
- The guarded claim is KEPT even though there is now one trigger. It still stops a&lt;br /&gt;
  double-submit, a second portal node, and a re-ingest racing an in-flight parse.&lt;br /&gt;
- Re-ingest parses immediately instead of queueing for a scheduler.&lt;br /&gt;
- The stall reaper runs when the review screen loads. There is no timer here any&lt;br /&gt;
  more, and a document stranded by a redeploy mid-parse only matters when somebody&lt;br /&gt;
  looks for it - which matters more now the parse lives in the web application.&lt;br /&gt;
- tabula moves to this module with its exclusions intact, as does the&lt;br /&gt;
  dumpCircularClasspath helper the local ingest harness depends on.&lt;br /&gt;
- Screen no longer claims &quot;the ingest job runs every 5 minutes&quot;, which was untrue the&lt;br /&gt;
  moment cron stopped being the route; poll interval 15s -&gt; 3s to match a parse that&lt;br /&gt;
  takes seconds. jsVersion 404 -&gt; 405.&lt;br /&gt;
- offer.circular.review.url added here, since the runner sends that email now.&lt;br /&gt;
&lt;br /&gt;
Verified: full ingest of the Aug&apos;26 circular through the relocated code is identical&lt;br /&gt;
to the reference - 239 offers, 663 products, 279 AUTO_EXACT, 361 benefits, 511&lt;br /&gt;
tenures, 911 bank links. ProductNamesTest 11/11 in its new home.&lt;/div&gt;~ /trunk/profitmandi-fofo/build.gradle&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/OfferCircularController.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/BankTextParser.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/BenefitParser.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CatalogIndex.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CircularExtractor.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CircularIngestRunner.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CircularIngestService.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/CircularRow.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/FootnoteParser.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/ProductAliases.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/ProductMatcher.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/ProductNames.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/ScopeConfig.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/SequenceRatio.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/TenureParser.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;~ /trunk/profitmandi-fofo/src/main/webapp/resources/js/offer-circular-review.js&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular&lt;br /&gt;+ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/ProductNamesTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;rev=37337</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;rev=37337</guid></item>
<item><pubDate>Tue, 18 Aug 2026 12:12:09 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37335 – Show offer circular ingest state on the review screen  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;Show offer circular ingest state on the review screen&lt;br /&gt;
&lt;br /&gt;
Upload and parsing run in different processes - the portal stores the PDF as DRAFT&lt;br /&gt;
and the cron job claims it minutes later - so the screen looked identical before and&lt;br /&gt;
after a successful ingest. A reviewer had no way to tell &quot;not parsed yet&quot; from&lt;br /&gt;
&quot;parsed and produced nothing&quot;, and a FAILED circular showed nothing at all.&lt;br /&gt;
&lt;br /&gt;
- the selected circular&apos;s state is shown as queued / parsing / parsed / failed,&lt;br /&gt;
  with the recorded reason on failure and the ingest summary on success&lt;br /&gt;
- while it is DRAFT or PROCESSING the screen polls every 15s and pulls in the rows&lt;br /&gt;
  the moment the parse lands. Polling stops as soon as the state settles, so it&lt;br /&gt;
  cannot spin forever, and a transient error keeps waiting rather than giving up&lt;br /&gt;
- jsVersion 403 -&gt; 404, since offer-circular-review.js is already being served and&lt;br /&gt;
  this is a modification rather than a new file&lt;br /&gt;
&lt;br /&gt;
Pairs with the stall reaper: a circular abandoned mid-parse is now both recovered&lt;br /&gt;
and explained on screen instead of sitting silently in PROCESSING.&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/offer-circular-review.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/offer-circular-review.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;rev=37335</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;rev=37335</guid></item>
<item><pubDate>Tue, 18 Aug 2026 00:19:29 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37331 – Add offer circular review and curation screen  Shows the ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 5 file(s) modified&lt;/strong&gt;&lt;br/&gt;Add offer circular review and curation screen&lt;br /&gt;
&lt;br /&gt;
Shows the nine verbatim PDF columns beside what the parser made of them, uploads a&lt;br /&gt;
new monthly circular, and resolves the products the matcher could not.&lt;br /&gt;
&lt;br /&gt;
Upload deliberately does not parse - it stores the PDF, sha256-deduped, and&lt;br /&gt;
registers it DRAFT, so an upload can never half-populate the offer tables. The cron&lt;br /&gt;
ingest job picks it up from there.&lt;br /&gt;
&lt;br /&gt;
The curation queue groups by distinct (division, raw text) because that is the&lt;br /&gt;
product_alias key: one answer clears every row carrying that text, on this circular&lt;br /&gt;
and on every later one. On the Aug&apos;26 circular that turns 152 unresolved rows into&lt;br /&gt;
106 decisions. Three actions mirror product_alias.action - PIN to a catalog id,&lt;br /&gt;
REWRITE to the catalog&apos;s spelling and match again, or IGNORE.&lt;br /&gt;
&lt;br /&gt;
- Writes product_alias only, so nothing the screen does can set manually_curated&lt;br /&gt;
  and lock a circular against re-ingest. Coverage decisions, which do need that,&lt;br /&gt;
  are listed but visibly parked rather than offered a naming answer.&lt;br /&gt;
- A saved decision changes nothing until re-ingest, because aliases are read at&lt;br /&gt;
  ingest time; the queue says so and the re-ingest button puts the document back&lt;br /&gt;
  to DRAFT for the scheduler. The portal cannot run the ingest itself - that lives&lt;br /&gt;
  in profitmandi-cron, which fofo does not depend on.&lt;br /&gt;
- The closest rejected match is shown for context and never pre-selected. Four new&lt;br /&gt;
  OnePlus models each &quot;nearly&quot; matched a 2015 OnePlus 2 at 0.80-0.84, and offering&lt;br /&gt;
  that as a suggestion invites a reviewer to confirm it. Where the catalog has no&lt;br /&gt;
  such SKU the search says so and steers to IGNORE.&lt;br /&gt;
- aliasExport emits every decision as replayable SQL, because the portal writes to&lt;br /&gt;
  one database and environments would otherwise drift apart silently.&lt;br /&gt;
&lt;br /&gt;
Access is an email allowlist AND the admin role. Both are enforced in the&lt;br /&gt;
controller; the sidebar entry repeats the allowlist because visibility in auth.menu&lt;br /&gt;
is role-driven and cannot express a per-email rule.&lt;br /&gt;
&lt;br /&gt;
No jsVersion bump: offer-circular-review.js is a new file that was never cached,&lt;br /&gt;
so it needs no cache-buster, and churning that shared counter only conflicts with&lt;br /&gt;
whoever is mid-edit on it.&lt;/div&gt;+ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/OfferCircularController.java&lt;br /&gt;+ /trunk/profitmandi-fofo/src/main/webapp/resources/js/offer-circular-review.js&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/webapp/WEB-INF/views/ftl/admin.vm&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/offer-circular-review.vm&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;rev=37331</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2F%2Ftrunk%2Fprofitmandi-fofo%2Fsrc%2Fmain%2Fwebapp%2Fresources%2Fjs%2Foffer-circular-review.js&amp;rev=37331</guid></item>
</channel></rss>