<?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-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/</title><description>WebSVN RSS feed &#x2013; SmartDukaan</description><lastBuildDate>Fri, 09 Oct 2026 01:04:41 +0530</lastBuildDate><generator>WebSVN 2.8.6-DEV</generator><language>en</language><link>https://svn.smartdukaan.com/log.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;max=40&amp;</link><atom:link href="https://svn.smartdukaan.com/rss.php?isdir=1&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;repname=SmartDukaan" rel="self" type="application/rss+xml" />
<item><pubDate>Thu, 10 Sep 2026 17:19:06 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37585 – Fix web-offer sync: selectModelOffers join order (Unknown column &apos;o.id&apos; in ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;Fix web-offer sync: selectModelOffers join order (Unknown column &apos;o.id&apos; in &apos;on clause&apos;)&lt;br /&gt;
&lt;br /&gt;
selectModelOffers led its FROM with offers.offer_product p and then joined&lt;br /&gt;
offers.offer_raw_row r ON r.offer_id = o.id, referencing alias o one join&lt;br /&gt;
before o was introduced. An ON clause resolves only against tables already&lt;br /&gt;
in the join order, so MySQL rejected it with SQLSyntaxErrorException:&lt;br /&gt;
Unknown column &apos;o.id&apos; in &apos;on clause&apos;. Every per-model sync since r37581 has&lt;br /&gt;
therefore failed - webOfferSync=FAILED on the 15:04 and 17:14 re-ingests of&lt;br /&gt;
document 4 - leaving the 166 legacy NULL-key row-badges active and zero&lt;br /&gt;
consolidated badges published.&lt;br /&gt;
&lt;br /&gt;
Reordered to lead with offers.offer o, matching the proven shape of the&lt;br /&gt;
sibling selectRowOffers query. All three are inner joins so the result set&lt;br /&gt;
is unchanged; BEST_OFFER_WINS and ORDER BY p.catalog_id still resolve.&lt;br /&gt;
&lt;br /&gt;
Verified by executing the corrected statement read-only against prod for&lt;br /&gt;
document 4: 733 rows over 314 distinct catalog ids, the expected model&lt;br /&gt;
count. Not caught by tests because all 53 offercircular tests are&lt;br /&gt;
stub-based (no Spring, no DB) and never execute this SQL.&lt;br /&gt;
&lt;br /&gt;
Failure was visible only because r37568 records webOfferSync= in&lt;br /&gt;
ingest_summary; the runner still swallows the exception by design.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37585</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37585</guid></item>
<item><pubDate>Thu, 10 Sep 2026 14:58:44 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37581 – web offer sync: retire the pre-consolidation badges instead of deleting ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer sync: retire the pre-consolidation badges instead of deleting them&lt;br /&gt;
&lt;br /&gt;
The sync now deactivates any CIRCULAR row with a NULL circular_offer_key on its next&lt;br /&gt;
run. A row-keyed badge is a fragment of what a consolidated badge says, so leaving it&lt;br /&gt;
active would show a partner the same offer twice - once whole and once in pieces.&lt;br /&gt;
&lt;br /&gt;
That removes the DELETE from the migration entirely, which is strictly better:&lt;br /&gt;
&lt;br /&gt;
  * nothing is destroyed, so a bad sync is one UPDATE away from being undone&lt;br /&gt;
  * web_offer_product has NO foreign key to web_offer, so the DELETE had to clear its&lt;br /&gt;
    532 rows separately or strand them as orphans&lt;br /&gt;
  * no window where a circular has no badges at all - the old ones stay live until the&lt;br /&gt;
    new ones exist&lt;br /&gt;
&lt;br /&gt;
The migration is now purely additive: one ALTER, safe to run ahead of the deploy, which&lt;br /&gt;
is how it was applied to prod.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/resources/sql/add_web_offer_per_model.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37581</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37581</guid></item>
<item><pubDate>Thu, 10 Sep 2026 14:55:17 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37580 – web offer: state an EMI scheme the circular gave without ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer: state an EMI scheme the circular gave without months&lt;br /&gt;
&lt;br /&gt;
  Rs.2,500 on Credit Card EMI (CIB) with IDFC First Bank, Kotak Mahindra Bank&lt;br /&gt;
&lt;br /&gt;
52 Sep&apos;26 offers have a bare &apos;CIB&apos; tenure cell - the circular names the EMI type and&lt;br /&gt;
gives no months. TenureParser correctly yields no tenure row for a cell with no digits,&lt;br /&gt;
so the type vanished and the badge said only &apos;on Credit Card EMI&apos;. Every one of those&lt;br /&gt;
52 carries a cashback, so it was 52 offers&apos; worth of SKUs silent about the EMI they&lt;br /&gt;
apply to.&lt;br /&gt;
&lt;br /&gt;
The type is stated because the circular stated it. The MONTHS are not invented,&lt;br /&gt;
because it did not give them - the same line the CIB expansion was left on.&lt;br /&gt;
&lt;br /&gt;
Read from offer_raw_row.col_emi_tenure rather than stored: &apos;scheme, no month&apos; is not a&lt;br /&gt;
tenure, and offer_tenure.tenure_months is NOT NULL, so persisting it would mean a fake&lt;br /&gt;
0 row standing for a fact that is not a tenure.&lt;br /&gt;
&lt;br /&gt;
Only ever attached to an EMI mode, and real tenures always win over the bare code.&lt;br /&gt;
&lt;br /&gt;
ModelOfferTest 8 -&gt; 11.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/offercircular/WebOfferSyncService.java&lt;br /&gt;~ /trunk/profitmandi-fofo/src/test/java/com/spice/profitmandi/web/offercircular/ModelOfferTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37580</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37580</guid></item>
<item><pubDate>Thu, 10 Sep 2026 13:46:45 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37578 – web offer sync: read what the circular grants each MODEL, ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer sync: read what the circular grants each MODEL, not each row&lt;br /&gt;
&lt;br /&gt;
selectModelOffers returns one row per (catalog_id, benefit), carrying the context that&lt;br /&gt;
qualifies it - the banks it applies to, its tenures and their scheme, the timing and&lt;br /&gt;
the window. Consolidation happens in the service; this is the read it needs.&lt;br /&gt;
&lt;br /&gt;
LEFT JOIN on the benefit, because a scheme-only offer carries no cashback and dropping&lt;br /&gt;
it here would lose the NCE/LCE badge entirely.&lt;br /&gt;
&lt;br /&gt;
Content-keyed writes alongside: selectSyncedByKey, insertKeyedWebOffer,&lt;br /&gt;
replaceProducts, deactivateMissingKeys. A badge is now identified by a sha256 of its&lt;br /&gt;
terms, so models with identical terms share one and a model appears in exactly one.&lt;br /&gt;
&lt;br /&gt;
Migration add_web_offer_per_model.sql adds circular_offer_key + its unique key, and&lt;br /&gt;
drops the row-keyed CIRCULAR badges - one of those is a fragment of what a&lt;br /&gt;
content-keyed badge says and there is no mapping from five fragments to one whole, so&lt;br /&gt;
they are regenerated by the next ingest.&lt;br /&gt;
&lt;br /&gt;
⚠️ web_offer_product has NO foreign key to web_offer, so its rows do not cascade and&lt;br /&gt;
are deleted explicitly or they are orphaned. web_offer_sync_shadow does cascade.&lt;br /&gt;
source=&apos;CIRCULAR&apos; only - the 3,850 hand-authored rows are never touched.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/add_web_offer_per_model.sql&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37578</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37578</guid></item>
<item><pubDate>Wed, 09 Sep 2026 14:42:05 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37555 – web offer sync: one value per SKU per payment mode ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer sync: one value per SKU per payment mode&lt;br /&gt;
&lt;br /&gt;
The circular says two things about the same phone. Motorola Sep&apos;26 page 9 names&lt;br /&gt;
&apos;G37 Power&apos; generically at Rs.1,000 CC Full Swipe (row 12) and &apos;G37 Power (8+128)&apos;&lt;br /&gt;
at Rs.2,000 (row 13), so G37 Power 8+128 carried both badges and a partner could&lt;br /&gt;
quote either.&lt;br /&gt;
&lt;br /&gt;
Precedence, per (catalog_id, txn_mode):&lt;br /&gt;
  1. a specifically named VARIANT beats a generic MODEL - the named line is the OEM&lt;br /&gt;
     being precise about that SKU&lt;br /&gt;
  2. at the same level, the higher value wins&lt;br /&gt;
  3. tie-break on lowest offer id, so the outcome is deterministic&lt;br /&gt;
&lt;br /&gt;
The generic line still covers every variant nobody named: G37 Power 4+64 keeps its&lt;br /&gt;
Rs.1,000 Full Swipe while 8+128 takes Rs.2,000. Verified on the live data - 1026311&lt;br /&gt;
now resolves to exactly CC_EMI 2500 and CC_FULL_SWIPE 2000, down from four competing&lt;br /&gt;
values.&lt;br /&gt;
&lt;br /&gt;
An offer keeps a SKU if it wins on at least one of its own modes, since one badge&lt;br /&gt;
carries every mode of its offer. Scheme-only offers are never filtered - no value to&lt;br /&gt;
compare.&lt;br /&gt;
&lt;br /&gt;
Deliberately NOT reusing v_offer_applicable, which encodes the same VARIANT-beats-&lt;br /&gt;
MODEL rule but has no document or status filter: once August is re-ingested its rows&lt;br /&gt;
enter that view and an EXPIRED August variant would silently suppress a live&lt;br /&gt;
September model. Scoping to one document avoids that; the view is left alone for&lt;br /&gt;
other consumers.&lt;br /&gt;
&lt;br /&gt;
Measured on Sep&apos;26: 557 product links -&gt; 458, 191 badges -&gt; 166.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37555</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37555</guid></item>
<item><pubDate>Wed, 09 Sep 2026 13:11:25 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37553 – web offer sync: all_banks is TINYINT(1), so never cast it ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 1 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer sync: all_banks is TINYINT(1), so never cast it to Number&lt;br /&gt;
&lt;br /&gt;
ClassCastException: java.lang.Boolean cannot be cast to java.lang.Number, thrown from&lt;br /&gt;
selectPublishableOffers on every ingest since 2026-09-08. Confirmed against the live&lt;br /&gt;
driver: SELECT all_banks returns java.lang.Boolean.&lt;br /&gt;
&lt;br /&gt;
MySQL Connector/J maps TINYINT(1) to Boolean while Hibernate may hand back a Number,&lt;br /&gt;
so the value must be read through isTrue() - the same shape as ScopeConfig.isTrue and&lt;br /&gt;
OfferScopeRepositoryImpl.isTrue, both of which exist for exactly this reason and both&lt;br /&gt;
of which I had in front of me when writing the cast.&lt;br /&gt;
&lt;br /&gt;
The failure was silent by design: CircularIngestRunner swallows sync exceptions so a&lt;br /&gt;
web-offer problem can never fail a good ingest. The circular kept publishing, the&lt;br /&gt;
document&apos;s processed_at kept moving, and the only symptom was that web_offer.synced_at&lt;br /&gt;
stopped advancing - which is what should have been checked before reporting the sync&lt;br /&gt;
as working on 8 September.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37553</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37553</guid></item>
<item><pubDate>Wed, 09 Sep 2026 12:36:26 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37549 – web offer sync: read tenures for scheme-only offers  selectTenures, ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer sync: read tenures for scheme-only offers&lt;br /&gt;
&lt;br /&gt;
selectTenures, keyed by offer id like the benefit and bank reads.&lt;br /&gt;
&lt;br /&gt;
Needed because an offer with no cashback is still a real offer - a no-cost or&lt;br /&gt;
low-cost EMI scheme - and its tenures are the only thing it has to say. Without them&lt;br /&gt;
those rows can only be described as &apos;NA&apos;.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37549</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37549</guid></item>
<item><pubDate>Tue, 08 Sep 2026 19:39:16 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37545 – web offer sync: read benefits and banks for the composed ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;web offer sync: read benefits and banks for the composed detail text&lt;br /&gt;
&lt;br /&gt;
selectBenefits and selectBanks, keyed by offer id and fetched once per circular&lt;br /&gt;
rather than per offer - 259 offers would otherwise be 518 extra round trips.&lt;br /&gt;
&lt;br /&gt;
The main query now also carries offer_id, benefit_timing and all_banks.&lt;br /&gt;
&lt;br /&gt;
Bank read takes INCLUDE rows only: an EXCLUDE is meaningful only when all_banks=1,&lt;br /&gt;
and such an offer is described as &apos;All banks&apos; rather than by listing an exclusion a&lt;br /&gt;
partner cannot act on.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37545</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37545</guid></item>
<item><pubDate>Thu, 03 Sep 2026 18:16:40 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37527 – offer circular: a new month supersedes every older one  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 4 file(s) modified&lt;/strong&gt;&lt;br/&gt;offer circular: a new month supersedes every older one&lt;br /&gt;
&lt;br /&gt;
Publishing a circular expires still-running offers from earlier circulars, at the&lt;br /&gt;
offers level and again for the web offers they produced.&lt;br /&gt;
&lt;br /&gt;
Why: the new circular restates whatever is still live, so leaving the old month&lt;br /&gt;
ACTIVE means the same cashback is current twice. Verified Aug&apos;26 -&gt; Sep&apos;26: all 24&lt;br /&gt;
SKUs covered by August&apos;s four still-running Apple offers were carried into&lt;br /&gt;
September, six of them twice.&lt;br /&gt;
&lt;br /&gt;
- expireOlderDocumentOffers: status ACTIVE -&gt; EXPIRED for earlier documents.&lt;br /&gt;
  end_date is deliberately NOT touched - it is what the OEM said, and older offers&lt;br /&gt;
  stay readable as reference. They simply stop being current.&lt;br /&gt;
- expireIfSuperseded: the converse, so re-ingesting an OLD circular while a newer&lt;br /&gt;
  one is live cannot resurrect it. With both, &apos;newest circular wins&apos; holds whatever&lt;br /&gt;
  order documents are ingested in.&lt;br /&gt;
- deactivateOlderPeriods / hasNewerPublishedPeriod do the same for dtr.web_offer.&lt;br /&gt;
&lt;br /&gt;
Verified on real data in a rolled-back transaction: publishing Sep expired 165&lt;br /&gt;
still-ACTIVE Aug offers (many stale since the 18 Aug ingest), Sep did not expire&lt;br /&gt;
itself, and re-ingesting Aug while Sep is live self-expired its 4 revived offers.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37527</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37527</guid></item>
<item><pubDate>Thu, 03 Sep 2026 17:43:36 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37525 – offer circular: division aliases, portal-editable scope, web offer sync (dao) ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 11 file(s) modified&lt;/strong&gt;&lt;br/&gt;offer circular: division aliases, portal-editable scope, web offer sync (dao)&lt;br /&gt;
&lt;br /&gt;
- division_alias support: CircularIngestRepository.selectDivisionAliases so an&lt;br /&gt;
  alternate OEM label resolves onto an existing division instead of dropping the&lt;br /&gt;
  rows as UNKNOWN. Both pdf_label columns are ALIASED - Hibernate discovers&lt;br /&gt;
  native-query results by name and throws NonUniqueDiscoveredSqlAlias on a dup.&lt;br /&gt;
&lt;br /&gt;
- OfferScopeRepository{,Impl}: write side for scope config (add/edit a division,&lt;br /&gt;
  in_scope toggle, label aliases). Kept apart from OfferCurationRepository, whose&lt;br /&gt;
  contract is limited to product_alias - a bad alias mismaps one product, a bad&lt;br /&gt;
  scope change silently drops a whole brand.&lt;br /&gt;
&lt;br /&gt;
- OfferCircularRepositoryImpl: label-side division join now resolves through&lt;br /&gt;
  division_alias (dva), otherwise an UNPARSED row under an aliased label is hidden&lt;br /&gt;
  by the inScopeOnly filter - exactly the rows the review screen exists to show.&lt;br /&gt;
  Also isoDate(): period_month left as java.sql.Date serialised to epoch millis,&lt;br /&gt;
  which an &amp;lt;input type=date&gt; silently rejects, so the circular filter cleared&lt;br /&gt;
  itself and every circular showed every row.&lt;br /&gt;
&lt;br /&gt;
- WebOfferSyncRepository{,Impl} + migration: publish a parsed circular into&lt;br /&gt;
  dtr.web_offer / web_offer_product. Anchored on (document, page, row) stored as&lt;br /&gt;
  VALUES, never offers.offer.id, which is recreated on every re-ingest. source&lt;br /&gt;
  defaults to MANUAL so the 3850 hand-typed rows are untouched; web_offer_sync_shadow&lt;br /&gt;
  is what lets a human edit win over a later sync.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferCircularRepositoryImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferScopeRepository.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferScopeRepositoryImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepository.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/WebOfferSyncRepositoryImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/resources/sql/add_web_offer_circular_sync.sql&lt;br /&gt;+ /trunk/profitmandi-dao/src/test/java/com/spice/profitmandi/dao/repository&lt;br /&gt;+ /trunk/profitmandi-dao/src/test/java/com/spice/profitmandi/dao/repository/offers&lt;br /&gt;+ /trunk/profitmandi-dao/src/test/java/com/spice/profitmandi/dao/repository/offers/OfferCircularDateSerialisationTest.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37525</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37525</guid></item>
<item><pubDate>Wed, 19 Aug 2026 20:32:53 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37363 – Offer circular ingest: return affected rows so INSERT IGNORE cannot ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Offer circular ingest: return affected rows so INSERT IGNORE cannot hide an FK failure&lt;br /&gt;
&lt;br /&gt;
insertBenefit/insertTenure/insertBank use INSERT IGNORE for idempotency, which also&lt;br /&gt;
makes MySQL downgrade a foreign key violation to a warning. Production was bootstrapped&lt;br /&gt;
without the bank / txn_mode / emi_scheme masters, so all 872 benefit and tenure inserts&lt;br /&gt;
were silently discarded: the ingest reported PUBLISHED with 239 offers carrying no&lt;br /&gt;
amounts, no tenures and no bank eligibility, and nothing anywhere said so.&lt;br /&gt;
&lt;br /&gt;
The three methods now return the affected row count (1 written, 0 discarded) so the&lt;br /&gt;
caller can count what landed rather than what it attempted.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37363</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37363</guid></item>
<item><pubDate>Tue, 18 Aug 2026 14:59:37 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37342 – Allow re-ingest to start a circular already sitting in DRAFT ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 2 file(s) modified&lt;/strong&gt;&lt;br/&gt;Allow re-ingest to start a circular already sitting in DRAFT&lt;br /&gt;
&lt;br /&gt;
Moving the parse into the portal turned DRAFT into a dead end. Under the cron&lt;br /&gt;
scheduler DRAFT meant &quot;something will pick me up&quot;, so re-ingest only ever had to push&lt;br /&gt;
a document back into it, and PUBLISHED/FAILED were the only sensible sources. Nothing&lt;br /&gt;
polls DRAFT any more - the runner is triggered by the upload that created the&lt;br /&gt;
document - so a circular whose trigger never fired had no way to be started at all.&lt;br /&gt;
&lt;br /&gt;
That is not hypothetical: the Aug&apos;26 circular uploaded to production before the runner&lt;br /&gt;
was deployed sits in DRAFT, and pressing re-ingest matched zero rows and reported&lt;br /&gt;
&quot;not started&quot;.&lt;br /&gt;
&lt;br /&gt;
DRAFT now joins PUBLISHED and FAILED as a valid source state. PROCESSING stays&lt;br /&gt;
excluded - that one is genuinely in flight - and claimForProcessing remains the single&lt;br /&gt;
arbiter of who actually parses, so allowing DRAFT cannot cause a double parse.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferCurationRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferCurationRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37342</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37342</guid></item>
<item><pubDate>Tue, 18 Aug 2026 12:11:38 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37333 – Reclaim offer circulars stranded in PROCESSING, and surface the ingest ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 3 file(s) modified&lt;/strong&gt;&lt;br/&gt;Reclaim offer circulars stranded in PROCESSING, and surface the ingest reason&lt;br /&gt;
&lt;br /&gt;
A claim moves a circular DRAFT -&gt; PROCESSING, and selectDraftDocumentIds only ever&lt;br /&gt;
picks up DRAFT. So a worker that died, was redeployed, or hung mid-parse left that&lt;br /&gt;
document stranded in PROCESSING forever, invisible to every later sweep. The batch&lt;br /&gt;
tier looked like it provided retry semantics and did not.&lt;br /&gt;
&lt;br /&gt;
- reclaimStalledProcessing(minutes) fails anything left in PROCESSING past the&lt;br /&gt;
  threshold. Deliberately FAILED and not back to DRAFT: a circular that reliably&lt;br /&gt;
  kills the parser would otherwise be re-claimed on every sweep forever. FAILED is&lt;br /&gt;
  visible, carries the reason, and the existing re-ingest action already allows&lt;br /&gt;
  FAILED -&gt; DRAFT, so re-queueing is one click.&lt;br /&gt;
- claimForProcessing now stamps processed_at, which is what the stall is measured&lt;br /&gt;
  against. No DDL: that column is written only by this repository and read by&lt;br /&gt;
  nothing else, so it can carry the last-transition time.&lt;br /&gt;
- selectDocuments returns ingest_error and ingest_summary. Without the reason the&lt;br /&gt;
  screen would show a bare FAILED, which the reaper would now produce routinely.&lt;br /&gt;
&lt;br /&gt;
Verified against the local DB both ways: a claim aged 45 minutes is reclaimed with&lt;br /&gt;
its reason recorded, a fresh claim is untouched.&lt;/div&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepository.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepositoryImpl.java&lt;br /&gt;~ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferCircularRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37333</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37333</guid></item>
<item><pubDate>Mon, 17 Aug 2026 21:07:00 +0530</pubDate><dc:creator>amit</dc:creator><title>Rev 37329 – Add offers-schema repositories for the Pine Labs affordability circular  ...</title><description>&lt;div&gt;&lt;strong&gt;amit – 7 file(s) modified&lt;/strong&gt;&lt;br/&gt;Add offers-schema repositories for the Pine Labs affordability circular&lt;br /&gt;
&lt;br /&gt;
Three repositories over the offers schema, split by who is allowed to write what:&lt;br /&gt;
&lt;br /&gt;
- OfferCircularRepository - read side for the review screen (verbatim rows,&lt;br /&gt;
  documents, per-offer parsed detail)&lt;br /&gt;
- CircularIngestRepository - write side for ingest; claims a DRAFT document with&lt;br /&gt;
  a guarded UPDATE and deletes only rows derived from that one document, so&lt;br /&gt;
  re-ingesting one month cannot disturb another&lt;br /&gt;
- OfferCurationRepository - write side for manual curation&lt;br /&gt;
&lt;br /&gt;
The split is deliberate: a caller that only displays circulars should not hold a&lt;br /&gt;
handle that can rewrite the scope config or the offer tables.&lt;br /&gt;
&lt;br /&gt;
OfferCurationRepository writes offers.product_alias and nothing else. An alias is&lt;br /&gt;
config, keyed on (division_id, raw_text), so re-ingest reproduces it and one&lt;br /&gt;
decision carries into every later circular. Writing offer_product instead would be&lt;br /&gt;
derived data that re-ingest deletes, which is why doing so has to set&lt;br /&gt;
manually_curated and freeze the circular permanently - not a trade worth making for&lt;br /&gt;
a naming decision, so this repository cannot make it.&lt;br /&gt;
&lt;br /&gt;
A PIN is validated against the division&apos;s own brand and category before it is&lt;br /&gt;
stored. Nothing downstream re-checks a pinned id - the matcher takes it at face&lt;br /&gt;
value - so an unverified exception would silently mismap money.&lt;/div&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepository.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/CircularIngestRepositoryImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferCircularRepository.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferCircularRepositoryImpl.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferCurationRepository.java&lt;br /&gt;+ /trunk/profitmandi-dao/src/main/java/com/spice/profitmandi/dao/repository/offers/OfferCurationRepositoryImpl.java&lt;br /&gt;</description><link>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37329</link><guid>https://svn.smartdukaan.com/revision.php?repname=SmartDukaan&amp;path=%2Ftrunk%2Fprofitmandi-dao%2Fsrc%2Fmain%2Fjava%2Fcom%2Fspice%2Fprofitmandi%2Fdao%2Frepository%2Foffers%2F&amp;isdir=1&amp;rev=37329</guid></item>
</channel></rss>