Subversion Repositories SmartDukaan

Rev

Go to most recent revision | Show changed files | Details | Compare with Previous | Blame | RSS feed

Filtering Options

Rev Age Author Path Log message Diff
37884 27 d 20 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/ fix(web): todayOffers for staff users; stop logging full Auth-Token

- /todayOffers (GlitchTip #59, 417 events): resolved the store via
dtr.user_accounts, which internal staff using the partner app don't have, so
getUserCart returned null and the call NPE'd. Use the retailerId from the
token (same value as the partner's saholic account); return an empty list
when the token carries no store.
- AuthenticationInterceptor: log only the last 6 characters of the
Auth-Token instead of the full JWT (was reaching GlitchTip breadcrumbs).
 
37882 27 d 20 h ranu /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/ activated imei will not get scratch coupon  
37879 28 d 2 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ refactor(web): stop setting removed inventory.warehouse fields on seller warehouse create

Follows dao r37878, which removed the never-read fields from Warehouse.
 
37874 31 d 20 h ranu /trunk/ recent winners of scratch offer  
37866 33 d 3 h ranu /trunk/ request login for b2b app for sales department enable  
37859 33 d 21 h amit /trunk/profitmandi-web/src/main/ fix(payment): send partners back to app.smartdukaan.com after wallet top-up via CCAvenue

r34902 moved angular.app.url to https://smartdukaan.com/, which does not serve the
partner app, so the post-payment redirect to pages/home/payment-status/{id} returned 404.
The payment itself was recorded; only the landing page was broken.

Also drops the extra slash in the redirect format (base URL already ends in /) and adds
the trailing slash to the dev value to match.
 
37856 34 d 3 h amit /trunk/profitmandi-web/src/main/resources/ docs(external-api): brandIdentifier is per itemId and returned on all SKU-level endpoints  
37852 34 d 20 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ fix(warehouse): V2 dashboards list ACTIVE warehouses instead of forcing 7573; courier/rider default warehouse 13368  
37847 34 d 21 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/ refactor(warehouse): read warehouse lists and labels from BillingWarehouseService instead of WAREHOUSE_MAP/WAREHOUSE_NAME_MAP  
37836 35 d 5 h aman /trunk/ Lead Management: the calendar date range now applies to follow-up leads too, in both the lead list and the CSV download. Previously follow-ups were appended undated, and the download (non-field-sales path) appended them even when the list did not, so a date-filtered download contained all follow-up leads from all time. 'All' status now consistently includes follow-ups in every branch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JjVXnkrysiXEa2YYRn4BqL
 
37821 38 d 20 h aman /trunk/ Lead Management: CSV download now also honours the lead table's search text (searchTerm), so the exported rows match the filtered rows on screen. Applies to both the fofo download and the V2 API download.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JjVXnkrysiXEa2YYRn4BqL
 
37820 38 d 21 h aman /trunk/ Lead Management: make Excel/CSV download honour the same filters as the on-screen list. V2 download no longer folds followUp into the status list when All is chosen (it skipped the status/color/date query and exported only follow-ups); fofo lead page re-selects every chosen status so Download sends the statuses the table was loaded with.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JjVXnkrysiXEa2YYRn4BqL
 
37793 42 d 0 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/ feat(cart): carry bag pricing via CarryBagQuote in V2 cart and order create

V2CartController prices and rebalances the carry bag through
CartService.getCarryBagQuote: one bag at Rs 1 per smartphone over Rs 12,000,
extras at listing, Bronze at listing for all. The old resolveCarryBagPrice /
CARRY_BAG_PREMIUM_PRICE path and its partnerTypeChangeService dependency are
removed. OrderController splits the blended carry bag line into its two
priced orders when partitioning the cart, so the same SKU appears twice on
one invoice at its two prices.

Needs profitmandi-dao r37792; deploy together with the partner apps.
 
37781 45 d 2 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/ feat(partner-access): demo partners in app switcher + impersonate

- /getPartners, /getPartnersList: position partners + active demo partners
(copies the cached getAuthUserPartnerEmailMapping set, never mutates it)
- /impersonate: an active demo grant also passes the access check

Needs dao r37779 and migration_demo_partner_access.sql applied.
 
37772 45 d 21 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ fix(supplier): V2 supplier save derives state from GSTIN  
37766 45 d 22 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/controller/fofo/ feat(store-closure): V2 closeStore goes through StoreClosureService; access checks read StoreAccess

Same rules as the fofo portal (dao r37764): reason, remark and approval mail required; mohit.gulati
removed from extend billing.
 
37759 46 d 20 h vikas /trunk/ LMS Call for App  
37742 48 d 23 h amit /trunk/profitmandi-web/src/main/java/com/spice/profitmandi/web/v2/exception/ v2: silence client disconnects and demote 4xx, matching the v1 taxonomy

r37728 added a client-disconnect handler to the v1 GlobalExceptionHandler and the
flood did not stop: #39 went on adding events, and every one of a 50-event sample
was from a /v2/ URL. V2GlobalExceptionHandler is scoped
basePackages="com.spice.profitmandi.web.v2", so v2 responses never reached the v1
handler at all and fell through to its own handleGenericException at ERROR --
~19,900 events, the second largest source on the board.

Worth recording because the first diagnosis was wrong. The theory was that an
exception raised while the response body is written cannot reach an @ExceptionHandler
because the response is already committed. It can: DispatcherServlet catches it out of
ha.handle() and still runs the resolvers. What it cannot do afterwards is WRITE the
substitute response. The handler runs and logs either way, which is precisely why
patching the wrong advice class changed nothing.

Adds @ExceptionHandler(IOException.class) here, delegating to the same
isClientDisconnect test the v1 handler uses -- duplicated rather than shared because
catalina is provided by the container and is not on this module's compile classpath,
so ClientAbortException cannot be imported and is matched on simple name plus the
messages a dead peer actually produces. A genuine IOException (full disk, a broken
pipe to something that is not the client) matches none of them and keeps its ERROR
and its 500. Returns null for a disconnect: the connection that would carry a body is
already gone, and writing to it is what raised this.

Also demotes five sibling handlers in the same file that were logging caller mistakes
at ERROR, which v1 has logged at WARN since the taxonomy work: business validation,
missing parameter, type mismatch, malformed body, method not supported, media type
not supported. v2 never received that pass. The business line also stops attaching a
stack trace -- a validation has nothing useful in one.

Left at ERROR deliberately, because they are real defects: IllegalArgument, NPE,
genuine IO failure, and the two catch-alls.
 
37733 49 d 3 h amit /trunk/profitmandi-web/src/main/ Remove dead third-party integrations: web

- PayU: /payu-pay and the payu-pay-response/cancelled handlers (bodies were
already commented out), PayuHandler, payment/ helpers, PayU POJOs, and the
PAYU PAY option served by checkout/payment-options.
PayuPayController stays: it holds the live CCAvenue, Razorpay and Pine Labs
callbacks.
- SmartPing: GET /click2call/{toMobile} (v1 + v2) and the caller-ID hook
/smartping/receipt + /v2/hookCallerID, which only logged
- HyperTrack: device location, partner location and geofence endpoints plus
HyperTrackService. The attendance endpoints (/getPunchHistory,
/employee/attendance) never called HyperTrack and are kept, moved to
EmployeeAttendanceController / V2EmployeeAttendanceController.
- Affiliate click-outs and live pricing (Amazon/Flipkart/Snapdeal via OMG):
ClicksController, LivePricingController and v2 wrappers. Live pricing was
already returning an empty list.
- Thriwe controller (fully commented out), SpiceMoney and FundFina v2 controllers
- Aramex branch of /track; tofee.* keys in dev/prod properties
 
37729 49 d 3 h amit /trunk/ lead: one workable lead per mobile, with a 6-month supersede and an L2+ override

There was no choke point for lead creation. Ten sites did `new Lead()` across four
modules -- three in web's LeadController, two in V2FofoLeadController, three in fofo's
LeadController, one in TrialServiceImpl and one in the cron LeadSyncRunner -- and only
ONE of them (fofo /createLead) checked for an existing lead at all. Result on live data:
5,137 mobiles carrying duplicate leads over 12,156 rows, worst case 29 on one number,
and two agents unknowingly working the same shop.

THE RULE, in new LeadCreationService, which all ten now route through:

no active lead on the number -> create
active, last activity >= 6 months -> retire the old one, create the new one, SILENTLY
active, last activity < 6 months -> BLOCK; only an L2+ user may override

Active = status in (pending, followUp) AND the assignee is still an active auth_user.
Last activity = GREATEST(lead.updated/created, MAX(lead_activity.created)).

The stale branch is deliberately quiet. A shop enquiring again after six months is a
handover, not a clash, and mailing on it would train the desk to ignore the alert -- so
only a genuine collision notifies. Live split: 195 stale against 1,241 fresh, and roughly
three blocks a month.

WHY "ACTIVE" ALSO MEANS A LIVE OWNER

331 open leads are assigned to 11 DEACTIVATED accounts (157 to sm@smartdukaan.com alone,
whose newest lead is from 2022). Counting them as active would block fresh enquiries
behind an account nobody can log in to and therefore nobody can close. Requiring a live
owner defuses all 331 without retiring a single row. Retirement here is only ever
REACTIVE -- triggered by a new entry on the same number. Nothing runs on a schedule.

ASSUMPTION worth flagging: a superseded lead becomes status=notInterested (stage DROPPED)
with closure_timestamp and reason 'Superseded after 6 months inactivity', rather than a
new `expired` status. "Closed" is an explicit allow-list in the UI --
Arrays.asList(notInterested, finalized) at V2FofoLeadController:150 and fofo
LeadController:313 -- and there are ~107 references to specific LeadStatus values, so a
new enum value would make these leads vanish from BOTH the open and closed screens.
Stage DROPPED keeps the nuance (the shop never said no) and still maps to notInterested
via LeadStage.toLegacyStatus().

OVERRIDE is L2+ in ANY team, not Call Center only: Sales L1 owns 1,063 of the 1,776 open
leads, so a Call-Center-only gate would funnel every team's collisions through three
people. The MAIL still goes to Call Center L2+, resolved from cs.position at send time
rather than hardcoded. An override is a TAKEOVER -- it closes the existing lead -- because
a second live lead is the exact thing the rule exists to prevent.

UNATTENDED CALLERS (cron sync, CSV upload, trial registration, AI intake) have nobody to
offer an override to, so they use createUnattended: skip the colliding row and mail the
desk rather than throwing. CSV reports imported/duplicateSkipped/duplicateMobiles back to
the operator instead of failing the whole file over one number.

ALSO FIXES selectByMobileNumber, which called getSingleResult and therefore threw
NonUniqueResultException on any mobile with more than one lead -- GlitchTip #99 and #1359,
both still firing. It now prefers the open lead, then the most recently touched.

NOT INCLUDED, deliberately: no DB unique constraint. 10 mobiles already carry more than
one open lead and would have to be resolved by hand first, which conflicts with the
no-auto-retirement rule. The service enforces the invariant going forward.

NEEDS A DBA STEP: user.lead.mobile is unindexed on 37,580 rows, so this check is a full
scan on every create. Index DDL is in the accompanying note; it has NOT been applied.
 

Show All