Skip to content

Commit

Permalink
Merge branch '4.3' into bugfix/email-property-on-order
Browse files Browse the repository at this point in the history
# Conflicts:
#	CHANGELOG.md
#	src/services/Customers.php
  • Loading branch information
nfourtythree committed Jul 13, 2023
2 parents 9d6c376 + a2e4754 commit 1f3d659
Show file tree
Hide file tree
Showing 21 changed files with 598 additions and 140 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 4.3.0 - Unreleased

- Guest customers registering during checkout now have their addresses saved to their account.
- Deprecated `craft\commerce\elements\Order::setEmail()`. `Order::setCustomer()` should be used instead.

## Unreleased
Expand All @@ -14,6 +15,7 @@
- Fixed a bug where address changes weren’t being synced to carts using them as a source. ([#3178](https://github.com/craftcms/commerce/issues/3178))
- Added `craft\commerce\services\Orders::afterSaveAddressHandler()`.
- Added `craft\commerce\elements\Order::$orderCompletedEmail`. ([#3138](https://github.com/craftcms/commerce/issues/3138))
- Added the `commerce/cart/forget-cart` action. ([#3206](https://github.com/craftcms/commerce/issues/3206))

## 4.2.11 - 2023-06-05

Expand Down
26 changes: 26 additions & 0 deletions example-templates/dist/shop/_private/address/fields.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{#
Outputs address form fields for editing an address.
#}
{% set showPrimaryCheckboxes = showPrimaryCheckboxes is defined ? showPrimaryCheckboxes : false %}
{% set addressFieldLayout = craft.app.getAddresses().getLayout() %}
{% set addressCustomFields = addressFieldLayout.getCustomFields()|filter(f => className(f) == 'craft\\fields\\PlainText') %}
{# @var address \craft\elements\Address #}
Expand Down Expand Up @@ -193,9 +194,34 @@ Outputs address form fields for editing an address.
{% endfor %}
</div>
{% endif %}

{% if showPrimaryCheckboxes %}
<hr class="my-2">
<div class="my-2">
{{ input('text', 'isPrimaryBilling', address.isPrimarybilling ? 1 : 0) }}
<label>{{ input('checkbox', 'isPrimaryBillingBox', 1, { checked: address.isPrimaryBilling, 'data-primary-input': 'isPrimaryBilling' }) }} {{ 'Use as the primary billing address'|t('commerce') }}</label>
</div>
<div class="my-2">
{{ input('text', 'isPrimaryShipping', address.isPrimaryShipping ? 1 : 0) }}
<label>{{ input('checkbox', 'isPrimaryShippingBox', 1, { checked: address.isPrimaryShipping, 'data-primary-input': 'isPrimaryShipping' }) }} {{ 'Use as the primary shipping address'|t('commerce') }}</label>
</div>
{% endif %}
</div>

{% js %}
{% if showPrimaryCheckboxes %}
document.querySelectorAll('input[type=checkbox][data-primary-input]').forEach(el => {
el.addEventListener('change', ev => {
let primaryInput = document.querySelector(`input[name="${ev.target.dataset.primaryInput}"]`);
if (ev.target.checked) {
primaryInput.value = 1;
} else {
primaryInput.value = 0;
}
});
});
{% endif %}

document.querySelector('select#{{ 'countryCode'|namespaceInputId(addressName) }}').addEventListener('change', ev => {
const countryCode = ev.target.value;
const stateSelect = document.querySelector('select#{{ 'administrativeArea'|namespaceInputId(addressName) }}');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Outputs the site’s global main navigation based on path and included `pages` a
<div class="absolute right-2 top-0">
{% if currentUser %}
<a href="{{ url('shop/customer') }}"
class="mx-2 px-2 py-1 rounded text-sm font-semibold">
{{- currentUser.email -}}
class="relative text-lg cursor-pointer inline-block mx-4 my-5 px-2 py-1 bg-white rounded-lg hover:shadow">
👤&nbsp;My Account
</a>
{% else %}
<a href="{{ url('shop/customer/sign-in') }}"
Expand All @@ -47,12 +47,15 @@ Outputs the site’s global main navigation based on path and included `pages` a
{% endif %}
<a href="{{ url('shop/cart') }}"
class="relative text-lg cursor-pointer inline-block mx-4 my-5 px-2 py-1 bg-white rounded-lg hover:shadow">
{% if cart.totalQty %}
<span class="absolute -mr-3 -mt-3 right-0 top-0 py-1 px-2 rounded-full text-white text-xs bg-blue-800">
{{- cart.totalQty -}}
{% if cart.totalQty %}
{{- cart.totalQty -}}
{% else %}
Empty
{% endif %}
</span>
{% endif %}
<p role="img" aria-label="{{ 'Shopping Cart'|t }}">🛒</p>

<span aria-label="{{ 'View Cart'|t }}">🛒 Cart</span>
</a>
</div>
</nav>
Expand Down
44 changes: 22 additions & 22 deletions example-templates/dist/shop/checkout/addresses.twig
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ Outputs a form for collecting an order’s shipping and billing address.
sourceIdName: 'sourceShippingAddressId',
}) }}

{% if currentUser and addresses|length %}
<div class="mt-3">
<label>
{{ input('checkbox', 'makePrimaryShippingAddress', 1, {
id: 'makePrimaryShippingAddress',
}) }}
{{ 'Make this my default shipping address'|t }}
</label>
</div>
{% endif %}

<hr class="my-5">

{{ hiddenInput('billingAddressSameAsShipping', 0) }}
Expand All @@ -57,17 +68,6 @@ Outputs a form for collecting an order’s shipping and billing address.
</label>
</div>

{% if currentUser %}
<div class="mt-3">
<label>
{{ input('checkbox', 'makePrimaryShippingAddress', 1, {
id: 'makePrimaryShippingAddress',
}) }}
{{ 'Make this my default shipping address'|t }}
</label>
</div>
{% endif %}

<div class="mt-8">
{{ include('shop/_private/address/fieldset', {
title: 'Billing Address'|t,
Expand All @@ -78,19 +78,19 @@ Outputs a form for collecting an order’s shipping and billing address.
}) }}
</div>

<hr class="my-5">

{% if currentUser %}
<div class="mt-3">
<label>
{{ input('checkbox', 'makePrimaryBillingAddress', 1, {
id: 'makePrimaryBillingAddress',
}) }}
{{ 'Make this my default billing address'|t }}
</label>
</div>
{% if currentUser and addresses|length %}
<div class="mt-3">
<label>
{{ input('checkbox', 'makePrimaryBillingAddress', 1, {
id: 'makePrimaryBillingAddress',
}) }}
{{ 'Make this my default billing address'|t }}
</label>
</div>
{% endif %}

<hr class="my-5">

<div class="mt-3 flex justify-end">
{{ tag('button', {
type: 'submit',
Expand Down
23 changes: 11 additions & 12 deletions example-templates/dist/shop/checkout/payment.twig
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,24 @@
{% set params = { currency: cart.paymentCurrency } %}
{% endif %}

{# Special params for Stripe Elements and Checkout#}
{# see https://stripe.com/docs/elements/appearance-api #}
{% if className(cart.gateway) == 'craft\\commerce\\stripe\\gateways\\PaymentIntents' %}
{% set params = {
paymentFormType: 'elements',
appearance: {
theme: 'stripe'
},
layout: {
type: 'tabs',
defaultCollapsed: false,
radios: false,
spacedAccordionItems: false
elementOptions: {
layout: {
type: 'accordion',
defaultCollapsed: false,
radios: false,
spacedAccordionItems: false
}
},
'submitButtonClasses': 'cursor-pointer rounded px-4 py-2 inline-block bg-blue-500 hover:bg-blue-600 text-white hover:text-white my-2',
'submitButtonLabel': 'Pay',
'errorMessageClasses': 'bg-red-200 text-red-600 my-2 p-2 rounded',
submitButtonClasses: 'cursor-pointer rounded px-4 py-2 inline-block bg-blue-500 hover:bg-blue-600 text-white hover:text-white my-2',
submitButtonLabel: 'Pay',
errorMessageClasses: 'bg-red-200 text-red-600 my-2 p-2 rounded',
} %}
{% dump params %}
{% endif %}
<div class="gateway-payment-form max-w-3/4">
{% namespace cart.gateway.handle|commercePaymentFormNamespace %}
Expand Down Expand Up @@ -131,7 +130,7 @@

{{ include('shop/checkout/_includes/partial-payment') }}

{% if cart.gateway.showPaymentFormSubmitButton() %}
{% if cart.paymentSourceId or cart.gateway.showPaymentFormSubmitButton() %}
<div class="mt-3 text-right">
{{ tag('button', {
type: 'submit',
Expand Down
1 change: 1 addition & 0 deletions example-templates/dist/shop/customer/addresses/edit.twig
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
{{ include('shop/_private/address/fields', {
address: address,
showLabelField: true,
showPrimaryCheckboxes: true,
}) }}
{{ hiddenInput('ownerId', currentUser.id) }}

Expand Down
68 changes: 42 additions & 26 deletions example-templates/dist/shop/customer/cards.twig
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@
</h1>

{% for gateway in gateways %}
<div>
{% if className(gateway) == 'craft\\commerce\\stripe\\gateways\\PaymentIntents' %}
<a class="my-2 text-blue-500 hover:text-blue-600" href="{{ gateway.billingPortalUrl(currentUser) }}">Manage cards on Stripe Billing portal &rarr;</a>
{% endif %}
</div>
<div class="mt-3 flex flex-wrap -mx-2">
{% set gatewayPaymentSources = craft.commerce.paymentSources.getAllPaymentSourcesByCustomerId(currentUser.id, gateway.id) %}
{% for paymentSource in gatewayPaymentSources %}
<div class="w-full mt-3 md:w-1/2 lg:w-1/3 px-2">
<div class="card bg-gray-100 border-blue-300 border-b-2 p-6">
<div class="my-3">
<strong>{{ paymentSource.description }} {% if paymentSource.id == currentUser.primaryPaymentSourceId %}({{ 'Primary'|t }}){% endif %}</strong>
<strong>{{ paymentSource.description }} {% if paymentSource.id == currentUser.primaryPaymentSourceId %}<span class="text-red-500">{{ 'Primary'|t }}</span>{% endif %}</strong>
{% if paymentSource.gateway %}
<div class="text-sm text-grey-dark">{{ paymentSource.gateway.name }} ({{ paymentSource.token }})</div>
{% endif %}
Expand Down Expand Up @@ -106,30 +111,33 @@
{{ hiddenInput('cancelUrl', '/shop/customer/cards'|hash) }}
{{ redirectInput('/shop/customer/cards') }}

<div class="gateway-payment-form max-w-3/4">
{{ gateway.getPaymentFormHtml({})|raw }}
</div>



{# Force in some basic styling for the gateway-provided form markup (better to build your own form markup!) #}
<style>
.gateway-payment-form input { padding: 0.5rem 1rem; width: 100%; margin-bottom: 1rem; line-height: 1.25; border: 1px solid rgba(209,213,219); border-radius: 0.25rem; }
.gateway-payment-form input:hover { border: 1px solid rgba(107,114,128); }
{# Column containers #}
.gateway-payment-form .grid,
.gateway-payment-form .card-data div div:nth-child(2) { display: flex; margin-right: -0.75rem; margin-left: -0.75rem; }
{# Columns #}
.gateway-payment-form .grid .item,
.gateway-payment-form input.card-expiry,
.gateway-payment-form input.card-cvc { width: 50%; margin-right: 0.75rem; margin-left: 0.75rem; }
</style>
{% set params = {} %}

{% if className(gateway) == 'craft\\commerce\\stripe\\gateways\\PaymentIntents' %}
{% set params = {
paymentFormType: 'elements',
appearance: {
theme: 'stripe'
},
elementOptions: {
layout: {
type: 'accordion',
defaultCollapsed: false,
radios: false,
spacedAccordionItems: false
}
},
submitButtonClasses: 'cursor-pointer rounded px-4 py-2 inline-block bg-blue-500 hover:bg-blue-600 text-white hover:text-white my-2',
submitButtonText: 'Create',
errorMessageClasses: 'bg-red-200 text-red-600 my-2 p-2 rounded',
} %}
{% endif %}

<div>
{{ input('text', 'description', '', {
maxlength: 70,
autocomplete: 'off',
placeholder: 'Card description'|t,
placeholder: 'Payment source description'|t,
class: ['w-full', 'border border-gray-300 hover:border-gray-500 px-4 py-2 leading-tight rounded']
}) }}
</div>
Expand All @@ -140,13 +148,21 @@
</label>
</div>

<div class="mt-4 text-right">
{{ tag('button', {
type: 'submit',
class: 'cursor-pointer rounded px-4 py-2 inline-block bg-blue-500 hover:bg-blue-600 text-white hover:text-white',
text: 'Add card'|t
}) }}
<div class="gateway-payment-form max-w-3/4">
{% namespace gateway.handle|commercePaymentFormNamespace %}
{{ gateway.getPaymentFormHtml(params)|raw }}
{% endnamespace %}
</div>

{% if gateway.showPaymentFormSubmitButton() %}
<div class="mt-4 text-right">
{{ tag('button', {
type: 'submit',
class: 'cursor-pointer rounded px-4 py-2 inline-block bg-blue-500 hover:bg-blue-600 text-white hover:text-white',
text: 'Add card'|t
}) }}
</div>
{% endif %}
</form>
</div>
{% endif %}
Expand Down
26 changes: 26 additions & 0 deletions example-templates/src/shop/_private/address/fields.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{#
Outputs address form fields for editing an address.
#}
{% set showPrimaryCheckboxes = showPrimaryCheckboxes is defined ? showPrimaryCheckboxes : false %}
{% set addressFieldLayout = craft.app.getAddresses().getLayout() %}
{% set addressCustomFields = addressFieldLayout.getCustomFields()|filter(f => className(f) == 'craft\\fields\\PlainText') %}
{# @var address \craft\elements\Address #}
Expand Down Expand Up @@ -193,9 +194,34 @@ Outputs address form fields for editing an address.
{% endfor %}
</div>
{% endif %}

{% if showPrimaryCheckboxes %}
<hr class="my-2">
<div class="my-2">
{{ input('text', 'isPrimaryBilling', address.isPrimarybilling ? 1 : 0) }}
<label>{{ input('checkbox', 'isPrimaryBillingBox', 1, { checked: address.isPrimaryBilling, 'data-primary-input': 'isPrimaryBilling' }) }} {{ 'Use as the primary billing address'|t('commerce') }}</label>
</div>
<div class="my-2">
{{ input('text', 'isPrimaryShipping', address.isPrimaryShipping ? 1 : 0) }}
<label>{{ input('checkbox', 'isPrimaryShippingBox', 1, { checked: address.isPrimaryShipping, 'data-primary-input': 'isPrimaryShipping' }) }} {{ 'Use as the primary shipping address'|t('commerce') }}</label>
</div>
{% endif %}
</div>

{% js %}
{% if showPrimaryCheckboxes %}
document.querySelectorAll('input[type=checkbox][data-primary-input]').forEach(el => {
el.addEventListener('change', ev => {
let primaryInput = document.querySelector(`input[name="${ev.target.dataset.primaryInput}"]`);
if (ev.target.checked) {
primaryInput.value = 1;
} else {
primaryInput.value = 0;
}
});
});
{% endif %}

document.querySelector('select#{{ 'countryCode'|namespaceInputId(addressName) }}').addEventListener('change', ev => {
const countryCode = ev.target.value;
const stateSelect = document.querySelector('select#{{ 'administrativeArea'|namespaceInputId(addressName) }}');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Outputs the site’s global main navigation based on path and included `pages` a
<div class="absolute right-2 top-0">
{% if currentUser %}
<a href="{{ url('[[folderName]]/customer') }}"
class="mx-2 px-2 py-1 rounded text-sm font-semibold">
{{- currentUser.email -}}
class="relative text-lg cursor-pointer inline-block mx-4 my-5 px-2 py-1 bg-white rounded-lg hover:shadow">
👤&nbsp;My Account
</a>
{% else %}
<a href="{{ url('[[folderName]]/customer/sign-in') }}"
Expand All @@ -47,12 +47,15 @@ Outputs the site’s global main navigation based on path and included `pages` a
{% endif %}
<a href="{{ url('[[folderName]]/cart') }}"
class="relative text-lg cursor-pointer inline-block mx-4 my-5 px-2 py-1 bg-white rounded-lg hover:shadow">
{% if cart.totalQty %}
<span class="absolute -mr-3 -mt-3 right-0 top-0 py-1 px-2 rounded-full text-white text-xs bg-[[color]]-800">
{{- cart.totalQty -}}
{% if cart.totalQty %}
{{- cart.totalQty -}}
{% else %}
Empty
{% endif %}
</span>
{% endif %}
<p role="img" aria-label="{{ 'Shopping Cart'|t }}">🛒</p>

<span aria-label="{{ 'View Cart'|t }}">🛒 Cart</span>
</a>
</div>
</nav>
Expand Down
Loading

0 comments on commit 1f3d659

Please sign in to comment.