Commit graph

1243 commits

Author SHA1 Message Date
e97d18bccd
MPS-21: public profile page, offer-history identity, shop offers inbox, actions hub rebuild
- Offer history & offer page show the buyer's display name (User.display_name
  = the public `name` handle; `full_name` is private) linked to a profile
  page — never the email. _serialize_offer drops buyer_email; events carry
  actor_name/actor_handle/actor_id, header carries buyer_name/buyer_handle.
- New public profile page: GET /profile/{handle} (views/user.py:user_profile,
  template profile.j2). Shows gravatar (User.gravatar_url(size) — forced
  identicon unless the user opted into Gravatar), member-since, owned/edited
  shops, and a <details> "Show email" that is server-gated: only the user
  themselves, or a shop owner/editor viewing in that shop's context
  (?shop={shop_id}) when the profile user has transacted there (an offer or
  an invoice).
- New operator offers inbox: GET /s/{shop_id}/offers (@shop_editor_required,
  shop_offers.j2) — open offers first, each row links to /o/{id} and the
  buyer's profile. Reachable from /actions/view via a new "Offers" button
  (shown when shop.offer_enabled).
- /actions/view rebuilt: one flat .action-button-grid (Grid auto-fit,
  minmax(15rem,1fr)) inside a properly-padded .action-columns well — fixes
  the off-balance two-column layout and buttons overflowing the well; no
  <br> spacers. Styleguide gains profile-card and action-button-grid
  patterns.
- offer.j2: buyer name shown (linked to profile); "Buyer:"/"Seller:" message
  lines renamed "Buyer note:"/"Seller note:" to disambiguate.

Tests: 11 new functional tests (profile render + email gating, offers inbox,
actions button, styleguide). 989 passed.
2026-05-12 17:47:24 -04:00
cb61227b2c
bump GIT_HASH to 227fc4e 2026-05-12 16:34:25 -04:00
227fc4e564
MPS-21: offer-page state notice + design-system Make-an-Offer settings form
- offer.j2 renders a state-aware notice (.offer-state-notice, .alert
  variants) above the action forms: declined / withdrawn / expired /
  accepted (+ pay-now hint for buyer) / your-turn / waiting — so the
  viewer always understands the offer state without depending on a flash
  a JS redirect would skip. _serialize_offer now exposes is_declined,
  is_withdrawn, is_expired, is_pending, is_countered, is_accepted.
- Shop-settings Make-an-Offer section restyled with the new
  .settings-form / .settings-form-grid / .settings-field /
  .settings-field-hint system (two-up grid, per-field hints, submit
  pinned right). Added a styleguide entry under #forms.
- Reworded the section blurb: auto-declined offers are NOT silent — the
  buyer is told their offer was too low; only the seller isn't pinged.
- Fixed --color-text-muted typo (→ --text-muted) on .offer-js-flash-info.

Tests: TestOfferRoutes gains 3 state-notice render tests;
TestSettingsFormStyleguide covers the styleguide + live shop-settings
markup and asserts the old wording is gone. 978 passed.
2026-05-12 16:34:21 -04:00
38b5739ce7
bump GIT_HASH to 2cad248 2026-05-12 12:04:28 -04:00
2cad2482b8
MPS-20/MPS-21: capability-driven presentation for auction & offer actions
Every bid/buy-now/watch and offer open/counter/accept/decline/withdraw
POST now works as a plain browser submit: flash + 302 redirect to the
auction/offer page. JSON is returned only when the request carries
X-Requested-With: XMLHttpRequest. Adds offer.js progressive-enhancement
layer (mirrors auction.js); pay-now CTA on accepted offers; .offer-js-flash
styling; grid layout for offer/action forms. offer_accept emails the
buyer only on the transition into ACCEPTED.

Tests: TestOfferRoutes/TestAuctionRoutes now drive the JSON path via an
AJAX helper; new TestOfferNoJsFallback/TestAuctionNoJsFallback cover the
plain-POST redirect path. 973 passed.
2026-05-12 12:04:19 -04:00
981b1316f2
bump GIT_HASH to a90979a 2026-05-12 11:13:11 -04:00
a90979a46c
MPS-23: single warm sending identity for transactional mail
All transactional mail now sends From app.email.sender (default
no-reply@origin.makepostsell.com) instead of per-shop no-reply@<domain>,
with the shop name (or email.from_name) as the display name. The origin
identity is DKIM-signed (d=makepostsell.com) and SPF-authorized and
relays via mx1's warm IP, so operator custom-domain shops stop getting
spam-foldered. format_from_header() builds the From; send_email() gained
a from_name kwarg. Reply-To / per-shop contact email still TODO.
2026-05-12 11:13:11 -04:00
0f19da5ba8
docs: add MPS-23 ticket — consolidated transactional sender identity 2026-05-12 11:07:38 -04:00
f4be4f4612
bump GIT_HASH to 9a0782e 2026-05-12 08:14:57 -04:00
9a0782e61f
verification-challenge: center on login-card, add 'try again' link to login page 2026-05-12 08:14:57 -04:00
4b96acae0c
bump GIT_HASH to f9b73bb 2026-05-11 18:14:12 -04:00
f9b73bb9de
product offer form: breathing room around bid + optional message
Per fox: "a touch more whitespace around the bid and optional message".
The expanded Make-an-offer form had the label, amount input, message
input, and submit button stacked flush against each other inside the
$42.00 well — no vertical rhythm.

New .product-offer-form CSS:
- display: grid; gap: var(--space-3, 12px)
- top margin var(--space-3) separates it from the summary button
- inputs get box-sizing: border-box, width: 100%, padding 8px 12px so
  they fill the column with comfortable internal spacing

Grid only.
2026-05-11 18:13:53 -04:00
9c00d52dfd
bump GIT_HASH to 5cad5c3 2026-05-11 17:30:11 -04:00
5cad5c3a0c
product page: 280px floor on the purchase column (two-column grid)
Per fox: the price / Add-To-Cart / Make-an-offer box gets squeezed too
narrow on mid-width viewports (960px–1200px) where the 2fr/1fr split
gives the 1fr column only ~250-300px, crushing the buttons.

section.two-column grid columns: minmax(0, 2fr) minmax(280px, 1fr)
- the images column can shrink (minmax(0, 2fr)) so the purchase
  column always gets its 280px minimum first
- once the viewport is wide enough, the columns return to the 2:1
  ratio up to the 1200px max-width

Grid only, no flex.

Tests pass (10 in target slices).
2026-05-11 17:29:55 -04:00
46dd2cb929
bump GIT_HASH to 2630b78 2026-05-11 12:55:34 -04:00
2630b78175
fix: .mps-button back to inline-block — inline-grid broke multi-child buttons
The inline-grid + place-items: center change put each child of a button
into its own grid row. Buttons that hold an icon span + label text (the
windows-95 hamburger: <span>☰</span> + "shop.unturf.com") got the icon
on one line and the label on the next.

.mps-button is now display: inline-block again — multi-child content
flows on one line as expected. The squish fix is retained without grid:
- box-sizing: border-box (normalizes <button> vs <a>)
- padding: 12px 18px (symmetric, generous horizontal — no more text
  jammed against the edge)
- line-height: 1.4 (explicit, not UA "normal")
- min-height: 44px (tap-target floor)
- appearance: none, font-family: inherit

.mps-button-primary likewise back to inline-block with box-sizing,
line-height, text-align: center.

(.edit-card-icon stays inline-grid + place-items: center — it holds a
single glyph, so grid centering is correct there. Still Grid only,
no flex anywhere.)

Tests pass (10 in target slices).
2026-05-11 12:55:14 -04:00
3af81a38e9
bump GIT_HASH to 7df421d 2026-05-11 10:44:33 -04:00
7df421dba3
fix: remove all flexbox — Grid only (CLAUDE.md transgression)
I shipped display:inline-flex / display:flex across .mps-button,
.mps-button-primary, .edit-card-icon, edit-page h3 headers,
.edit-status-bar, .edit-status-pill, .edit-save-bar,
.upload-thumbnails-header, .upload-thumbnail-item, and an inline
style on the torrent_opt_in label — all violations of the project's
Grid-only rule. fox caught it. All converted:

- .mps-button / .mps-button-primary / .edit-card-icon:
  display: inline-grid; place-items: center  (was inline-flex + center)
- edit-page h3 headers (icon + title):
  display: grid; grid-template-columns: auto 1fr; align-items: center
- .edit-status-bar: text-align: right + inline-grid pills that flow/wrap
  (was flex + flex-wrap + justify-content: flex-end)
- .edit-status-pill: display: inline-grid; grid-auto-flow: column
- .edit-save-bar: display: grid; grid-template-columns: 1fr auto
- .upload-thumbnails-header: display: grid; grid-template-columns: 1fr auto
  with a max-width: 600px media query collapsing to 1fr
- .upload-thumbnail-item: display: grid; grid-auto-rows: min-content;
  align-content: space-between  (replaces the flex margin-top: auto trick
  for pinning the upload form to the bottom of the stretched cell)
- torrent_opt_in label inline style: display:grid;grid-template-columns:auto 1fr

CLAUDE.md updated: the CSS-layout rule now spells out the Grid
equivalent for every flex pattern, clarifies which alignment
properties ARE valid in grid context, and includes a dated SHAME LOG
entry for this transgression.

Tests pass (11 in target slices).
2026-05-11 10:44:11 -04:00
cec78ccd45
bump GIT_HASH to 37e314d 2026-05-11 09:45:37 -04:00
37e314d534
cache-bust static CSS with ?v={git_hash} on every deploy
Browsers were caching /static/css/common.css indefinitely (the <link>
had no version param), so CSS fixes didn't show up until a hard
refresh. Fox kept seeing the old squished-button CSS after deploys.

- New request property request.git_hash (reified) returns the short
  git hash baked in at deploy time (views.version.GIT_HASH)
- base.j2 tokens.css and common.css links now carry ?v={{ request.git_hash }}

Each deploy bumps GIT_HASH, so the CSS URL changes, so browsers fetch
the fresh file. No more stale-CSS confusion.
2026-05-11 09:45:17 -04:00
40d25edb6d
bump GIT_HASH to 8853a5a 2026-05-11 08:19:31 -04:00
8853a5aa08
fix: .mps-button squished on <button> elements — normalize box model
Per fox: Add To Cart / Make an offer buttons looked squished (text
crammed at top, little vertical space) while .mps-button on <a>
elements (cart page) looked fine.

Root cause: <button> elements inherit UA-stylesheet line-height and
box-sizing that differ from <a>. The class set padding-top/bottom: 14px
but with the native button line-height the text didn't center properly.

Normalized .mps-button:
- appearance: none (+ -webkit-) — strip native button chrome
- box-sizing: border-box — consistent across <button>/<a>/<input>
- font-family: inherit — buttons default to a different font
- line-height: 1.4 — explicit, was relying on UA "normal"
- padding: 12px 16px (was 14px 0) — symmetric, gives horizontal
  breathing room too
- vertical-align: middle

Now <button class="mps-button">, <a class="mps-button">, and
<input type=submit class="mps-button"> all render the same.

Tests pass (9 in pricing_mode slice).
2026-05-11 08:19:18 -04:00
08ba11ab9d
bump GIT_HASH to d593062 2026-05-11 07:28:09 -04:00
d593062e6b
product page: owner sees "offers enabled" indicator instead of nothing
Per fox: "i only see add to cart not offer" — viewing their own
offer-mode (3/4) product as the shop owner showed just Add To Cart
with no sign that offers were active. The Make-an-offer form is
correctly hidden for owners (can't offer on your own product, same
as auctions), but that left owners with no feedback.

Now when product.offers_allowed and the viewer is a shop owner,
the page shows:
  ✓ Offers enabled — buyers see a "Make an offer" button here.
    You can't offer on your own product.

Buyers (non-owner, logged in) still see the expandable offer form.
Anon visitors still see "Log in to make an offer".

Updated test_make_offer_hidden_for_seller: owner now asserts no
Submit Offer button + no "Log in to make an offer" CTA, but DOES
see "Offers enabled" indicator.
2026-05-11 07:27:55 -04:00
d56c49f3ee
bump GIT_HASH to ee4bd86 2026-05-11 06:38:42 -04:00
ee4bd862ce
fix: pricing_mode never saved — handler gated on absent "submit" param
Root cause found via prod debug log: the product edit form's
onsubmit="submit.disabled = true" handler disables the submit button
before the browser collects form data, so the "submit" key is never
sent in the POST. The pricing_mode / allow_offers / auction-config
block was gated on `if "submit" in request.params:` — always False —
so it never ran. Hence no flash, no save.

The standard handlers (title, description, price, visibility) don't
have this gate; they check whether the field's value changed. The
pricing_mode block now follows the same pattern: gated on
`if "pricing_mode" in request.params:` (that radio only appears on
the product-title-and-description edit form, so other forms on the
page — uploads, inventory, bundle — don't trigger it).

- pricing_mode: read request.params["pricing_mode"], apply if valid
  and changed; immediate flush; flash; auto-create draft auction when
  switching into auction mode
- allow_offers: only processed when "allow_offers" in request.params
  (so a different form submitting won't reset the override)
- auction config block: unchanged, still inside the pricing_mode gate
- torrent_opt_in: also re-gated on "pricing_mode" in params instead of
  "submit" (was equally broken, just masked by the torrent kill switch)

Removed all the temporary debug logging (ENTER line, /opt and /tmp
file writes, journalctl warning).

Tests pass (15 in pricing_mode + auction-config slices).
2026-05-11 06:38:26 -04:00
938fda3e4a
bump GIT_HASH to a186b4d 2026-05-10 20:06:37 -04:00
a186b4d000
debug: log every product_edit view hit + use /opt path for log
The /tmp/mps-pricing-debug.log file didn't appear after fox triggered
a save attempt. Two changes to narrow down why:

1. Move the debug log to /opt/make_post_sell/pricing-debug.log (where
   uwsgi has owner write access) with /tmp as fallback. PrivateTmp or
   permissions might be blocking /tmp writes on this systemd setup.

2. Add an ENTER log line at the top of product_edit() that fires for
   every request — GET, POST, save, etc. If this line never appears,
   the view itself isn't being reached and the form is going somewhere
   else. If it appears but the pricing_mode line doesn't, the submit
   field is missing from params.
2026-05-10 20:06:24 -04:00
5c2694d7ae
bump GIT_HASH to 08b5440 2026-05-10 19:20:07 -04:00
08b5440cab
edit page: title at top + preview file as separate column + file log
Layout restructure per fox:
- "Edit Title, Description, or Visibility" rendered first at top of the
  edit grid (full width) via CSS order: 1. Useful info (title, price,
  pricing mode, visibility) is now the primary focus when landing on
  the page.
- "Upload or Replace Preview File" extracted into its own <section
  class="upload-preview well2"> sibling. It sits in the right column
  of the same row as "Upload or Replace Product File" via the natural
  2-col grid flow.
- Visual order: title-and-description → upload-product → upload-preview
  → upload-thumbnails → price-history. Implemented via CSS order
  property so HTML structure stays simple.
- Preview section only renders for digital sellable products (not bundle,
  not physical) — same guard as before but now an explicit conditional
  around the new <section>.

Debug:
- pricing_mode handler now ALSO writes to /tmp/mps-pricing-debug.log
  (world-writable) in addition to the journalctl warning. Lets us read
  POST params on prod without sudo. Will be removed when bug is fixed.

Tests still pass (9 pricing_mode tests).
2026-05-10 19:19:53 -04:00
5cc17a39a3
bump GIT_HASH to 84a2412 2026-05-10 18:34:17 -04:00
84a241221d
edit page: move status pills into call_to_action header area
Per fox: status data was "in the wrong spot" — it had been rendered at
the top of the content area as a standalone full-width row above the
edit-page grid. Moved into the call_to_action block (top-right of the
page, same area where the permanent link lives) so the at-a-glance
state sits naturally above the form rather than splitting visual flow.

- Pills (visibility / ready / price) and permanent link now render
  together in call_to_action
- .edit-status-bar restyled: no background, no border, right-justified
  flex row (matches the right-aligned page header area)
- .edit-permanent-link: right-aligned, muted, small

Tests still pass (9 in target slice).
2026-05-10 18:34:03 -04:00
9495452e98
bump GIT_HASH to dbc7453 2026-05-10 18:27:01 -04:00
dbc7453a4e
edit page: thumbnail item card layout, consistent heights, fills width
Per fox: thumbnails "not aligned properly" and "not using horizontal
space properly". Two issues:

1) Grid was at minmax(240px, 1fr) which on the full-card-width row
   often fit 3 columns instead of 4 (240 * 4 + gaps > available
   space). Lowered to minmax(200px, 1fr) so the auto-fit gives 4
   columns on a standard desktop edit card.

2) Each upload-thumbnail-item now renders as a sub-card:
   - flex-direction: column with consistent gap
   - background --surface-dim, --color-border, --radius-md
   - preview image fixed 140px height + object-fit: contain so all
     thumbnails align even when some slots are empty or have different
     aspect ratios
   - form pushed to bottom via margin-top: auto, so the upload buttons
     line up across cells regardless of how much text is above
   - p.bold-text break-word so long filenames don't blow out the cell
   - the legacy <hr/> separator between items is hidden inside the grid
     (it was a vertical-flow artifact)

The grid uses align-items: stretch so all 4 cells have equal height.

Tests still pass (9 in target slice).
2026-05-10 18:26:50 -04:00
d194fc5e18
edit page: thumbnails header flex row, grid for thumbnails below
Per fox: the thumbnails card layout was a mess — the h3, descriptor
text, and thumbnail items were all crammed into a single grid with
auto-fit columns, so thumbnail 1+2 sat on the same row as the header
and thumbnails 3+4 wrapped to row 2 leaving the left half empty.

Fix: restructure to a proper header + grid:

  <section class="upload-thumbnails well2 edit-card-full">
    <div class="upload-thumbnails-header">
      <h3>... icon + title ...</h3>
      <p class="upload-thumbnails-hint">Your cover ...</p>
    </div>
    <div class="upload-thumbnails-grid">
      <div class="upload-thumbnail-item">...</div>
      ... (4 thumbnails)
    </div>
  </section>

CSS:
- .upload-thumbnails-header: flex row, space-between, wraps on narrow
  screens; h3 grows, hint right-aligned + max-width 320px
- .upload-thumbnails-grid: auto-fit minmax(240px, 1fr) for the 4
  thumbnail slots, gap --space-4

Result: header reads cleanly across the top with the cover descriptor
on the right, and all 4 thumbnails sit in a clean grid below.

Tests still pass (9 in target slice).
2026-05-10 18:25:30 -04:00
b874b07d44
bump GIT_HASH to 64e1d8b 2026-05-10 17:45:08 -04:00
64e1d8bd3c
edit page: thumbnail + edit-details cards span both columns
Per fox: "🎨 Upload or Replace Thumbnail Files ... should be in a row
that spans two columns" — and the same for "Edit Title, Description,
or Visibility".

Both cards now get class edit-card-full, which sets grid-column: 1 / -1
so they span the entire row in the 2-column edit grid. The thumbnail
grid has up to 4 thumbnails that need room; the edit-details card
has a wide form with pricing-mode radios and description textarea.

New CSS:
  div.edit-page > section.edit-card-full { grid-column: 1 / -1; }

Styleguide updated with a live half/half/full example demonstrating
the pattern.
2026-05-10 17:44:50 -04:00
36da4e33ee
bump GIT_HASH to 705271e 2026-05-10 16:26:44 -04:00
705271ec76
edit page: Material-style cards, status bar, primary save action
Per fox: "make this look awesome", "use styleguide", "think material
design to make it stand out as to what to do".

Status bar at top of edit page — three pills surface the product's
current state in one glance:
- Visibility: Public (blue) / Unlisted (purple) / Private (gray)
- Ready to sell (green) / Missing required files (gold warning)
- Current price (gray)

The pills tell the owner immediately what's done and what isn't.

Section cards (.well2 on edit page) get Material-card treatment:
- Background, rounded corners, border, elevation-1 shadow
- Hover/focus-within bumps to elevation-3 (subtle lift)
- h3 header gets a 36px circular icon badge (.edit-card-icon),
  thin bottom border separating header from content
- Icons: 📁 product file, 📺 preview, 🎨 thumbnails, ✏️ details,
  📦 inventory, 📦 bundle

Primary save action: Save Settings button is now a filled,
prominent CTA (navy bg, white text, bold, elevation-1 shadow that
lifts to elevation-2 on hover, disabled state dims). Class
.mps-button-primary on the styleguide for reuse.

.edit-save-bar provides a sticky-bottom save container CSS for a
follow-up wrapper around the Save Settings input (not yet wired
into product_edit.j2 — same hash adds the CSS so it's available).

All wired into the styleguide:
- Status bar + 3 pill states (public ready, private incomplete, etc.)
- Section card with icon header (3 example cards)
- Primary save action button

Tokens used (with fallbacks for safety): --elevation-1/3, --radius-lg,
--radius-pill, --color-navy/navy-dark, --color-blue-tint, --space-N,
--motion-fast, --color-green-dark, --color-gold, --color-purple.

Tests still pass (10 in target slice).
2026-05-10 16:26:30 -04:00
2c63c60118
bump GIT_HASH to ea58c12 2026-05-10 16:09:38 -04:00
ea58c12fda
edit page: file-meta line + thumbnail labels + merged file stats
Per fox's feedback on shop.unturf.com edit page:

- File Type and File Size now stack on a single line with · separator
  (was 2 stacked <p> tags). Class file-meta on the wrapper, file-meta-item
  on each child. Applied to product, preview, thumbnail blocks.

- File Statistics removed as a standalone well; "Total capacity" line
  moved into the upload-product well at top, using the same file-meta
  pattern. Eliminates the half-empty 4th column in the 2-col grid.

- Thumbnail upload sections now have an <h4 class="thumbnail-label">
  showing thumbnail1 / thumbnail2 / etc. so owners can tell which slot
  is the cover (thumbnail1 shows on search pages) vs additional images.

- Description label split fix: the label, helper text, and textarea
  are now properly stacked. The section.product-title-and-description
  rule (display: grid for product page) is overridden to display: block
  on the edit page so the form flows normally.

- Helper text under the Description label uses <small class="form-help">
  with token-based styling.

- Textarea max-width 600px lifted on the edit page so it fills the
  available well width.

Styleguide entries added at /styleguide for: file-meta line, thumbnail
label, form-help.

Tests still pass (10 in target slice).
2026-05-10 16:09:29 -04:00
843130d2a9
bump GIT_HASH to 966c61e 2026-05-10 15:20:13 -04:00
966c61ec04
edit page: styleguide-driven layout + pricing_mode debug log
UI (per fox: "use styleguide to make this edit page way way better"):
- div.edit-page now max-width 1200px, centered, with token-based gap
- wells get larger internal padding (--space-4 + --space-5) so content
  isn't crammed against the well edge
- well h3:first-child resets margin-top and uses 1.125rem / 600 weight
- fieldsets inside edit page get tokens-based border, padding, legend
  styling that matches the rest of the design system

Debug:
- TEMPORARY log line in product_edit pricing_mode handler logs the raw
  POST params for the pricing_mode field plus the submit value. Will
  remove once the prod save-revert issue is diagnosed. Fox reports
  saving "Make an offer with buy-now" reverts to fixed price; cannot
  reproduce locally. Log will show whether the form is sending the
  field at all when fox saves.

Total: tests still pass (9 pricing_mode + 15 in target slice).
2026-05-10 15:19:58 -04:00
abab69ea3c
bump GIT_HASH to 0652f8c 2026-05-10 14:01:59 -04:00
0652f8cf31
MPS-20 + edit page: defensive pricing_mode flush + 2-col grid layout
Two fixes in one commit:

1) defensive: flush pricing_mode change to DB immediately after the
   radio writes it, instead of relying on the trailing
   product_modified-block flush at end of view. Fox reported saving
   "Make an offer with buy-now" reverts to fixed price; could not
   reproduce locally. Direct flush eliminates any code path between
   the radio change and end-of-view that might raise and abort the
   txn before the deferred save.

2) layout: div.edit-page goes from auto-fit minmax(240px, 1fr)
   (fits 4+ wells on wide screens) to a strict 2-column max grid:
   1 column on mobile, exactly 2 columns above 720px. The 4 wells
   on the product edit page now stack 2x2 instead of 4-across.

Tests:
- test_flip_to_offer_with_buy_now_mode_4_persists — direct POST
  pricing_mode=4 (Make Offer with Buy Now) persists
- test_flip_from_3_to_4_persists — Offer-only → Offer+buy-now
  transition persists
- test_render_form_then_submit_mode_4_via_form — fetches the rendered
  edit form via webtest and submits it back with mode=4 selected; the
  closest reproduction of fox's browser flow

All three pass locally. The save path is correct in the test harness.
If the prod issue persists after this commit, it's almost certainly
a browser-level issue (form not sending the field), not server-side.

Total: 961 tests pass (was 958 + 3).
2026-05-10 14:01:47 -04:00
5fbaf8fbfa
bump GIT_HASH to 891f289 2026-05-10 10:52:20 -04:00
891f2899b2
MPS-20: auction quantity (lot size) + full owner config form
Lets a shop owner auction a portion of inventory rather than all of it,
and reach every auction field from the product edit form (today's flow
only flipped pricing_mode and left start/end/reserve/buy-now unreachable).

Schema:
- mps_auction.quantity (Integer, default 1, server_default="1") —
  how many units this auction sells. Digital products force 1.
- Idempotent migration 1a419114ddf7 (column_exists guard)

Model:
- MpsAuction.is_lot_auction property (quantity > 1)

Owner-side form (product_edit.j2 + views/product.py):
- All auction config fields editable while state == DRAFT:
  quantity (physical only), start/end (datetime-local), start_price,
  reserve_price, buy_now_price (modes 2/4 only), bid_increment,
  soft_close_seconds
- "Schedule auction" checkbox flips DRAFT → SCHEDULED (or → ACTIVE
  if start_timestamp is already past)
- Validates end > start; blocks scheduling when invalid
- Locks all fields once SCHEDULED to preserve bidder trust
  (no rules-changes mid-flight)
- views/product.py serializes auction timestamps to YYYY-MM-DDTHH:MM
  for the datetime-local input

Cart integration:
- auction_checkout view sets cart.set_product_quantity(product, auction.quantity)
  so the cart success path's update_inventory() naturally deducts
  the right number of physical units. Cart total still uses the
  winning bid amount via auction_offer_override_in_cents — quantity
  affects inventory only, not price.

Tests:
- 2 unit (test_models.py): is_lot_auction default False, True for
  quantity > 1 (multiple values)
- 7 functional (test_functional.py): set quantity on physical auction,
  digital quantity forced to 1, schedule with future start →
  SCHEDULED, schedule with passed start → ACTIVE, end-before-start
  rejected, locked fields not overwritten after scheduled,
  auction_checkout sets cart quantity to lot size

Total: 958 tests pass (was 949 + 9).
2026-05-10 10:52:11 -04:00
4f751c6c03
bump GIT_HASH to 364af1f 2026-05-10 09:26:11 -04:00
364af1fcca
MPS-20 + MPS-21: fix physical Add To Cart bypassing auction/offer
Defect: product.j2 always rendered "Add To Cart" at list price for
physical products, even when pricing_mode=1 (auction only) or
pricing_mode=3 (offer only). A buyer browsing a physical auction
could click Add To Cart and pay list price, completely bypassing
the bidding flow.

Fix: wrap the physical Add To Cart / Sold Out branches in
{% if product.is_buy_now_allowed %} so they only render in modes
that permit direct purchase (0 fixed, 2 auction+buy_now, 4 offer+
buy_now). Modes 1 (auction-only) and 3 (offer-only) hide both the
Add To Cart button and the Sold Out indicator entirely; buyers must
use the View Auction or Make Offer entry points.

Tests:
- test_digital_fixed_price_shows_add_to_cart
- test_digital_auction_only_hides_add_to_cart
- test_digital_auction_with_buy_now_shows_add_to_cart
- test_digital_offer_only_hides_add_to_cart
- test_physical_auction_only_hides_add_to_cart (the regression fix)
- test_physical_offer_only_hides_add_to_cart (same)

Total: 949 tests pass (was 943 + 6).
2026-05-10 09:26:02 -04:00
d79082c6ff
bump GIT_HASH to 5e13a59 2026-05-09 21:46:47 -04:00