| Rev |
Age |
Author |
Path |
Log message |
Diff |
| 37427 |
45 d 5 h |
ranu |
/trunk/profitmandi-fofo/src/main/ |
src dashboard logic correction |
|
| 37409 |
45 d 12 h |
vikas |
/trunk/ |
Changed WhatsApp service to botpenguin (DigiWaha) |
|
| 37405 |
46 d 2 h |
amit |
/trunk/profitmandi-fofo/src/main/ |
Drive the onboarding/HR state dropdowns from inventory.statemaster
fofo-form.vm, fofo-edit.vm and hr_employee_form.vm each hardcoded their own state
list instead of using $stateNames. Six of those 37 values do not exist in the
master (& vs and variants, Uttaranchal, the pre-merger UTs), so anything picked
from them could not be resolved back.
Only the name="state" select changed in hr_employee_form.vm; its other dropdowns
are untouched. |
|
| 37400 |
46 d 4 h |
amit |
/trunk/profitmandi-fofo/src/main/ |
Merge the three sale-invoice download endpoints into /invoice/download
generateInvoice, generateInvoices and downloadInvoices differed only in how they
resolved the order ids and who was allowed to ask; everything after that was the
same. That drift meant only the single-order download stapled the policy
certificates, so the same invoice pulled from sale history came out without
them. One handler now selects by orderId, partner date range (admin only) or the
caller's own sale-history search, over reusable resolvers plus a shared
render-and-respond step. The old URLs stay as deprecated shims.
The admin range download is now fault tolerant - one unbillable order used to
fail the whole batch.
Remove the commented-out thermal variant of generateInvoice and the unused
paymentOptionIdPaymentOptionMapUsingPaymentOptions. Bump the asset version for
the sale.js change. |
|
| 37390 |
47 d 7 h |
ranu |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
total show on warehouse wise stock value on item detail |
|
| 37389 |
47 d 7 h |
ranu |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
total show on warehouse wise stock value on item detail |
|
| 37385 |
47 d 11 h |
vikas |
/trunk/profitmandi-fofo/src/main/ |
Added Notice and PJP access to akhil.kumar@smartdukaan.com |
|
| 37380 |
50 d 6 h |
amit |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
Fix /saleDetails 500 on insurance-only orders and null billing name/phone
Two defects on the sale-details screen, both from a legitimately-empty source.
1. /saleDetails 500s on an insurance-only order. A policy is not a catalog item,
so an insurance sale carries no fofo_order_item row; itemIds comes out empty and
itemRepository.selectByIds hits GenericRepositoryImpl.selectAllByInOrderByDesc,
which throws "List should not be empty" to guard against an empty IN (). The
same guard already exists two methods below at the sale-search site, so this
carries it across to the detail site. 346 orders across 95 partners are affected
- every insurance-only order ever written. The screen already loads the policies
and the view renders them, so nothing else was needed to display the sale.
2. Billing name and phone rendered as the literal
.getName(). A plain POS sale does not require an
address (only insurance does), so ~140k orders across 1038 partners carry
customerAddressId 0 and the lookup returns null. The existing guard covered the
address *string* but the object was added to the model unconditionally, and
Velocity prints an unresolvable reference verbatim. Fall back to the customer's
own name and mobile, which the invoice PDF already does via
OrderServiceImpl.createCustomAddressWithoutId - so screen and invoice now agree.
The fallback is transient and never persisted; a missing customer row is
swallowed deliberately, since this feeds a display field and throwing would turn
blank text into a 500.
Applied at both model-writing sites in this controller. |
|
| 37378 |
50 d 10 h |
amit |
/trunk/profitmandi-fofo/src/main/ |
Put the action-pending returns at the top of Sale Returns, and filter by partner
Sorting the received list pending-first changed nothing on screen, because every return
that still needs an action was missing from it. The list was built from purchase return
orders inside the date window, and a return order only exists once the warehouse has
received the goods - so a debit note awaiting receipt had no row to sort, and a return
sitting unrefunded for weeks fell out of the window entirely.
The screen is now two lists:
- Action Pending, on top, with no date bound. It merges the three shapes a pending return
takes - a debit note never received, a return order received but unrefunded, and one
rejected but not yet acknowledged - into a single row type, oldest first, with the age
in days beside it. Each row carries only the action that actually applies to it
- Settled Returns below, refunded and cancelled only, still bound to From/To. The pending
rows were lifted out of it, so nothing is listed twice
Two things worth recording:
- a debit note has no warehouse of its own. It is placed through the item's invoice and
the order that invoice was raised on, and a note that cannot be placed is dropped rather
than shown to a warehouse it may not belong to
- debit notes raised before the receive/refund flow existed were settled the old way and
cannot be worked from this screen. The cutoff is read from the earliest return order in
the database, so it needs no maintenance, and the page says so in a footnote instead of
quietly hiding them
The partner filter reuses the shared /partners typeahead and passes the id down into both
queries. Only a picked suggestion filters, so a half-typed name cannot blank the page. Its
handlers sit inline in the template, next to the markup they drive, following the pattern
add-wallet-request.vm already uses - which leaves the now-unused #invoice-return-date-apply
handler in return.js dead, to be removed with the return.js work already in flight.
Rendered offline through Velocity with the app's own directive.set.null.allowed to confirm
all four action variants emit the right buttons. |
|
| 37374 |
51 d 6 h |
ranu |
/trunk/ |
total show on warehouse wise stock value on item detail |
|
| 37355 |
52 d 11 h |
aman |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
AI lead intake (fofo, live): assign new leads to a random active BGC L1 instead of the hardcoded Khushbu/Archana round-robin |
|
| 37348 |
53 d 6 h |
ranu |
/trunk/ |
super retailer club 5 live |
|
| 37346 |
53 d 8 h |
amit |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
Sort sale returns so the ones still needing an action come first
The Recently Received Debit Notes table was ordered purely by receive time, so a
return waiting on a refund or on the partner's acknowledgment sank below rows that
were already refunded and needed nothing. On a busy warehouse the actionable rows
were off the first screen.
- recentOrders is now ranked pending-first (Received - Pending Refund, Rejected -
Pending Acknowledgment) ahead of settled ones (Refunded, Cancelled), with the
existing receiveTimestamp DESC kept as the tie-breaker inside each group
- getPendingActionRank follows the same precedence invoice-return.vm uses to pick
the status badge - reject checked before refund - so the ordering can never
disagree with the label the user sees
- ranked on the return's own state, not on the viewer's canReceive/canRefund
permissions, so a pending return stays at the top for everyone looking at it
Presentation only; no query, entity or lifecycle change. Note that returns never
received at all cannot surface here regardless, since the query filters on
receiveTimestamp BETWEEN the selected dates. |
|
| 37345 |
53 d 8 h |
vikas |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
Beat Journey (today): LOI-based 'Onboarded' + last-billing recency board columns, level-filtered orders list (grouped by partner), and flag tuning — remove #1/#3, use per-visit total_distance for #4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
|
| 37343 |
53 d 9 h |
vikas |
/trunk/profitmandi-fofo/src/main/ |
Update PJP, Visit quality flags |
|
| 37337 |
53 d 11 h |
amit |
/trunk/profitmandi-fofo/ |
Move offer-circular ingest out of cron and into the portal
The parse now runs in profitmandi-fofo, on a background thread, triggered by the
upload that produced the document.
Why: splitting one feature across two artifacts with independent deploy cadences
cost a full day. fofo shipped, cron did not, and a valid upload sat in DRAFT with
nothing on the server able to parse it - the deployed cron jar contained none of the
ingest classes. One 9-page PDF a month never justified a batch tier, and the portal
already ships two PDF stacks, so the isolation argument for keeping PDFBox out was
weaker than it looked.
- 13 parser classes move verbatim from com.smartdukaan.cron.offercircular to
com.spice.profitmandi.web.offercircular. No logic changed.
- CircularIngestScheduler becomes CircularIngestRunner: the @Scheduled(every 5 min)
entry point and the offer.circular.ingest.enabled flag are gone, replaced by a
single-threaded daemon executor. All claim, ingest and notification logic is
unchanged.
- Upload hands the document id to the runner AFTER COMMIT, not inline. The DRAFT row
is written inside the request transaction; a worker starting immediately would race
that commit, find nothing to claim and silently do nothing - which is precisely the
stuck-on-DRAFT symptom this change removes.
- The guarded claim is KEPT even though there is now one trigger. It still stops a
double-submit, a second portal node, and a re-ingest racing an in-flight parse.
- Re-ingest parses immediately instead of queueing for a scheduler.
- The stall reaper runs when the review screen loads. There is no timer here any
more, and a document stranded by a redeploy mid-parse only matters when somebody
looks for it - which matters more now the parse lives in the web application.
- tabula moves to this module with its exclusions intact, as does the
dumpCircularClasspath helper the local ingest harness depends on.
- Screen no longer claims "the ingest job runs every 5 minutes", which was untrue the
moment cron stopped being the route; poll interval 15s -> 3s to match a parse that
takes seconds. jsVersion 404 -> 405.
- offer.circular.review.url added here, since the runner sends that email now.
Verified: full ingest of the Aug'26 circular through the relocated code is identical
to the reference - 239 offers, 663 products, 279 AUTO_EXACT, 361 benefits, 511
tenures, 911 bank links. ProductNamesTest 11/11 in its new home. |
|
| 37332 |
53 d 13 h |
amit |
/trunk/profitmandi-fofo/src/main/ |
Move the offer-circular upload directory off a developer home path
Every upload in production failed with a 400 on mkdirs. offer.circular.dir was
never set in any environment, so it fell back to the code default
/users/amit/uploads/offer-circulars; Tomcat runs as the tomcat user, which cannot
create /users at the filesystem root, and the controller threw "Circular storage
directory is not writable".
- default is now /var/lib/smartdukaan/offer-circulars, a real server path
- offer.circular.dir set explicitly in prod.properties, and pointed at the
developer's own space in dev.properties, since /var/lib needs sudo on a
workstation
- staging.properties deliberately untouched; the new default covers it
The location has two hard constraints, now recorded on the field itself:
- OUTSIDE webapps/. A redeploy wipes anything under it, and
offer_document.stored_path is how both re-ingest and re-download resolve the
PDF, so a wipe breaks them permanently. Stray PDFs are already sitting in
WEB-INF/classes/META-INF on the server from exactly this mistake.
- OUTSIDE any web root. A circular carries the OEM's confidential cashback
economics and must never be servable as a static file. Hence /var/lib rather
than /var/www, whose local precedent /var/www/partner_stats is chmod 777.
Only fofo needs the key: the cron ingest resolves the PDF from
offer_document.stored_path and reads it as root, so 0750 tomcat:tomcat is enough.
Deploying this alone does not fix production - the directory must also exist and
be writable by tomcat. |
|
| 37331 |
54 d 0 h |
amit |
/trunk/profitmandi-fofo/src/main/ |
Add offer circular review and curation screen
Shows the nine verbatim PDF columns beside what the parser made of them, uploads a
new monthly circular, and resolves the products the matcher could not.
Upload deliberately does not parse - it stores the PDF, sha256-deduped, and
registers it DRAFT, so an upload can never half-populate the offer tables. The cron
ingest job picks it up from there.
The curation queue groups by distinct (division, raw text) because that is the
product_alias key: one answer clears every row carrying that text, on this circular
and on every later one. On the Aug'26 circular that turns 152 unresolved rows into
106 decisions. Three actions mirror product_alias.action - PIN to a catalog id,
REWRITE to the catalog's spelling and match again, or IGNORE.
- Writes product_alias only, so nothing the screen does can set manually_curated
and lock a circular against re-ingest. Coverage decisions, which do need that,
are listed but visibly parked rather than offered a naming answer.
- A saved decision changes nothing until re-ingest, because aliases are read at
ingest time; the queue says so and the re-ingest button puts the document back
to DRAFT for the scheduler. The portal cannot run the ingest itself - that lives
in profitmandi-cron, which fofo does not depend on.
- The closest rejected match is shown for context and never pre-selected. Four new
OnePlus models each "nearly" matched a 2015 OnePlus 2 at 0.80-0.84, and offering
that as a suggestion invites a reviewer to confirm it. Where the catalog has no
such SKU the search says so and steers to IGNORE.
- aliasExport emits every decision as replayable SQL, because the portal writes to
one database and environments would otherwise drift apart silently.
Access is an email allowlist AND the admin role. Both are enforced in the
controller; the sidebar entry repeats the allowlist because visibility in auth.menu
is role-driven and cannot express a per-email rule.
No jsVersion bump: offer-circular-review.js is a new file that was never cached,
so it needs no cache-buster, and churning that shared counter only conflicts with
whoever is mid-edit on it. |
|
| 37327 |
54 d 7 h |
ranu |
/trunk/ |
super retailer club 5 live |
|
| 37324 |
54 d 8 h |
aman |
/trunk/profitmandi-fofo/src/main/java/com/spice/profitmandi/web/controller/ |
Lead Management: restrict lead view to field-level sales only (L1-L3). Any SALES position at any level previously forced the own+reportees lead filter, so senior sales heads (L4+ BM/RSM/NSM/co-founder L7) lost visibility of all leads and their dashboard charts collapsed. hasCategory check replaced with isFieldSales() at both view-filter sites; assignee validation untouched. |
|