metatroncubeswdev 365e45406a Bundle Offers Shopify app: discount function, admin, storefront, deploy stack
Rust discount function (one automatic discount evaluating all offers in priority
order, parity with the Odoo engine), React Router admin with Polaris, theme app
extension and app proxy pages, webhooks incl. GDPR, managed-pricing limits, and
a Docker Compose stack (Postgres + Caddy HTTPS) for a single VPS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:35:58 -04:00

87 lines
3.5 KiB
Plaintext

{% doc %}
Offer card (F19): image or a 2x2 grid of product pictures, badge, name, deal, and for fixed bundles the
bundle price, the struck-through regular price and the number of items; end date; link to the bundle page.
Fixed-bundle prices come from live product prices (all_products, presentment currency); bundle-offers.js
recomputes $-off / bundle-price deals when the customer shops in another currency.
@param {object} offer - An offer from the app's storefront data
@param {string} [heading_tag] - h2 or h3 (default h3)
@example
{% render 'bo-card', offer: offer %}
{% enddoc %}
{%- liquid
assign url = '/apps/bundles/' | append: offer.h
assign tag = heading_tag | default: 'h3'
assign locale = request.locale.iso_code
assign name = offer.n
assign badge = offer.b
if offer.i[locale].n != blank
assign name = offer.i[locale].n
endif
if offer.i[locale].b != blank
assign badge = offer.i[locale].b
endif
assign regular = 0
if offer.t == 'fixed'
for line in offer.l
assign p = all_products[line.h]
if p.id
assign price = p.price
if line.v != ''
for variant in p.variants
assign vid = variant.id | append: ''
if vid == line.v
assign price = variant.price
endif
endfor
endif
assign line_total = price | times: line.q
assign regular = regular | plus: line_total
endif
endfor
assign dv_cents = offer.dv | times: 100
case offer.dt
when 'percent'
assign saving = regular | times: offer.dv | divided_by: 100.0 | round
when 'amount'
assign saving = dv_cents | at_most: regular
else
assign saving = regular | minus: dv_cents | at_least: 0
endcase
assign bundle = regular | minus: saving
endif
-%}
<article class="bo-card">
<a class="bo-card__media" href="{{ url }}" tabindex="-1" aria-hidden="true">
{%- if offer.img != blank -%}
<img src="{{ offer.img }}" alt="" loading="lazy" width="800" height="600">
{%- elsif offer.th.size > 0 -%}
<span class="bo-card__thumbs bo-card__thumbs--{{ offer.th.size | at_most: 4 }}">
{%- for src in offer.th limit: 4 -%}<img src="{{ src }}" alt="" loading="lazy" width="200" height="200">{%- endfor -%}
</span>
{%- endif -%}
</a>
{%- if badge != blank -%}<p class="bo-stub"><span>{{ badge }}</span></p>{%- endif -%}
<div class="bo-card__body">
<{{ tag }} class="bo-card__title"><a href="{{ url }}">{{ name }}</a></{{ tag }}>
<p class="bo-card__deal">{% render 'bo-summary', offer: offer %}</p>
{%- if offer.t == 'fixed' and regular > 0 -%}
<p class="bo-card__prices" data-bo-fixed data-regular="{{ regular }}" data-dt="{{ offer.dt }}" data-dv="{{ offer.dv }}">
<span class="bo-visually-hidden">{{ 'bundle_offers.card.bundle_price' | t }}</span>
<span class="bo-card__now" data-bo-bundle>{{ bundle | money }}</span>
{%- if saving > 0 -%}
<span class="bo-visually-hidden">{{ 'bundle_offers.card.regular_price' | t }}</span>
<s class="bo-card__was" data-bo-regular>{{ regular | money }}</s>
{%- endif -%}
<span class="bo-card__count">{{ 'bundle_offers.card.items' | t: count: offer.ni }}</span>
</p>
{%- endif -%}
{%- if offer.e != blank -%}
{%- assign ends = offer.e | time_tag: format: 'date' -%}
<p class="bo-card__ends">{{ 'bundle_offers.card.ends_html' | t: date: ends }}</p>
{%- endif -%}
<a class="bo-button" href="{{ url }}">{{ 'bundle_offers.card.shop' | t }}</a>
</div>
</article>