Skip to content

Commit

Permalink
[0.2] Feat - Discounts (#324)
Browse files Browse the repository at this point in the history
* Init

* Add discount to composer

* Initial test set up

* Initial discounts

* Tweaking discounts

* Tweaking bits

* Revert bits

* Try and show some freebies

* Discount work

* Discount tweaks

* Cast and add active scope

* Starting UI set up

* Introduce rulesets

* Refactor to rules

* Apply fixes from StyleCI

* Add helper to get data

* Add line count

* Add cart total rule

* Apply fixes from StyleCI

* Start of discounts in core

* Discount tweaks

* Apply fixes from StyleCI

* Start of discounts ui

* Add method to return types

* Import CartLine

* Fix migration name

* Fix name

* Logic updates

* Apply fixes from StyleCI

* Fix import

* Refactor discounts a touch

* UI tweaks

* Remove PRO package code

* Discount updates

* Apply fixes from StyleCI

* Docs and tweaks

* Apply fixes from StyleCI

* Add missing method

* Update composer.json

* Discount editing updates

* Apply fixes from StyleCI

* Fix up tests

* Add some tests

* Update tests

* Discount tweaks

* Apply fixes from StyleCI

* Editing updates

* Fixes

* Apply fixes from StyleCI

* Update CouponTest.php

* Apply fixes from StyleCI

* Add ability to delete discounts

* Pint updates

* Namespace update

* Update coupon.blade.php

* 🍺

* Update discounts.md

* Update CartManager.php

* Discount updates

* Pint updates

* Add min spend

* Update AbstractDiscount.php

* Update CouponTest.php

* Update DiscountCreate.php

* Allow brands to attach to discounts

* Support brand ids

* Update DiscountManager.php

* 🍺

* Add discount validation and tests

* Pint updates

* Update product discount saving

* 🍺

* Product discount updates

* Create ProductDiscountTest.php

* Add more editable fields

* Formatting

* Pint updates

* Add caching to cart's properties and reuse cartmanager instance, rather than keep creating a new one

* 🍺

* Move tax breakdown objects

* 🍺

* Add Discount value object

* wip

* Update Cart.php

* Update Cart.php

* wip

* Fixing tests

* 🍺

* Update CreateOrderTest.php

* Update CartManager.php

* Fix stuff

* Add cart-level discounts

* Add cart free items collection and move stuff around

* Initial tests

* Tweaks

* Update CartManager.php

* Update CartLineManager.php

* Update CachesPropertiesTest.php

* Update CachesPropertiesTest.php

* Discount updates

* 🍺

* Fix tests

* Update CouponTest.php

* Update DiscountManagerTest.php

* Update CouponTest.php

* Update composer.json

* Update composer.json

* Update discounts.php

* Update AdminHubServiceProvider.php

* Add max uses

* Add missing permissions

* Update app.css

* Update DiscountCreate.php

* Update product-discount.blade.php

* Update product-discount.blade.php

* Update ProductDiscount.php

* 🐝

* Discount updates

* Discount updates

* Update datepicker.blade.php

* Discount editing

* Brand UI updates

* Tweak collection saving

* Discount UI updates

* Compile assets

* Start discount refactor

* Discount ui

* Rework discount UI

* Discount updates

* Discount UI tweaks

* 🍺

* Tweak discount manager test

* Add channel setting

* Test updates

* Update DiscountManagerTest.php

* Tests and PINT

* UI Updates

* Update buy-x-get-y.blade.php

* Update discount.blade.php

* Update AbstractDiscount.php

* UI Tweaks

* Update for collection select

* Compile

* Update validation messages

* Update discount.blade.php

* Rename migrations

* Validation tweaks

* 🐝

* Fix up validation

* Validation tweaks

* 🐝

* Update AbstractDiscount.php

* Update buy-x-get-y.blade.php

* Fixes

* Update Discount.php

* Fixes

* Update buy-x-get-y.blade.php

* Update table

Co-authored-by: StyleCI Bot <bot@styleci.io>
Co-authored-by: Glenn Jacobs <glenn@neondigital.co.uk>
  • Loading branch information
3 people authored Dec 13, 2022
1 parent ac47798 commit c43f023
Show file tree
Hide file tree
Showing 95 changed files with 4,537 additions and 41 deletions.
1 change: 1 addition & 0 deletions docs/src/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ module.exports = {
'/lunar/carts',
'/lunar/channels',
'/lunar/collections',
'/lunar/discounts',
'/lunar/currencies',
'/lunar/customers',
'/lunar/images',
Expand Down
185 changes: 185 additions & 0 deletions docs/src/lunar/discounts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# Discounts

[[toc]]

## Overview

// ...

## Discounts

```php
Lunar\Models\Discount
```

|Field|Description|Example|
|:-|:-|:-|
|`id`|||
|`name`|The given name for the discount||
|`handle`|The unique handle for the discount||
|`type`|The type of discount|`Lunar\DiscountTypes\Coupon`|
|`data`|JSON|Any data to be used by the type class
|`starts_at`|The datetime the discount starts (required)|
|`ends_at`|The datetime the discount expires, if `NULL` it won't expire|
|`uses`|How many uses the discount has had|
|`max_uses`|The maximum times this discount can be applied storewide|
|`priority`|The order of priority|
|`stop`|Whether this discount will stop others after propagating|
|`created_at`|||
|`updated_at`|||

### Creating a discount

```php
Lunar\Models\Discount::create([
'name' => '20% Coupon',
'handle' => '20_coupon',
'type' => 'Lunar\DiscountTypes\Coupon',
'data' => [
'coupon' => '20OFF',
'min_prices' => [
'USD' => 2000 // $20
],
],
'starts_at' => '2022-06-17 13:30:55',
'ends_at' => null,
'max_uses' => null,
])
```

## Discount Purchasable

You can relate a purchasable to a discount via this model. Each has a type for whether it's a `condition` or `reward`.

- `condition` - If your discount requires these purchasable models to be in the cart to activate
- `reward` - Once the conditions are met, discount one of more of these purchasable models.

```php
Lunar\Models\DiscountPurchasable
```

|Field|Description|Example|
|:-|:-|:-|
|`id`|||
|`discount_id`|||
|`purchasable_type`||`Lunar\Models\ProductVariant`
|`type`|`condition` or `reward`|
|`created_at`|||
|`updated_at`|||

### Relationships

- Purchasables `discount_purchasables`
- Users - `customer_user`


## Usage

Fetching applied discounts

```php
use Lunar\Facades\Discounts;

$appliedDiscounts = Discounts::getApplied();
```

This will return a collection of discounts which are applied to the current cart.

```php
foreach ($appliedDiscounts as $item) {
// Lunar\Base\DataTransferObjects\CartDiscount
$item->cartLine; // Lunar\Models\CartLine
$item->discount; // Lunar\Models\Discount
}
```

Each cart line will also have a `discount` property populated with the model of the applied discount.

```php
foreach ($cart->lines as $line) {
$line->discount; // Lunar\Models\Discount;
}
```

:::tip
These aren't database relationships and will only persist for the lifecycle of the each request.
:::


### Adding your own Discount type


```php
namespace App\Discounts;

use Lunar\Base\DataTransferObjects\CartDiscount;
use Lunar\DataTypes\Price;
use Lunar\Facades\Discounts;
use Lunar\Models\CartLine;
use Lunar\Models\Discount;

class CustomDiscount
{
protected Discount $discount;

/**
* Set the data for the discount to user.
*
* @param array $data
* @return self
*/
public function with(Discount $discount): self
{
$this->discount = $discount;

return $this;
}

/**
* Return the name of the discount.
*
* @return string
*/
public function getName(): string
{
return 'Custom Discount';
}

/**
* Called just before cart totals are calculated.
*
* @return CartLine
*/
public function execute(CartLine $cartLine): CartLine
{
$data = $this->discount->data;

// Return the unaltered cart line back
if (! $conditionIsMet) {
return $cartLine;
}

$cartLine->discount = $this->discount;

$cartLine->discountTotal = new Price(
$cartLine->unitPrice->value * $discountQuantity,
$cartLine->cart->currency,
1
);

Discounts::addApplied(
new CartDiscount($cartLine, $this->discount)
);

return $cartLine;
}
}

```

```php
Discounts::addType(
CustomDiscount::class
);
```

2 changes: 1 addition & 1 deletion packages/admin/public/app.css

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/admin/resources/icons/outline/arrows-right-left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/admin/resources/icons/solid/arrows-right-left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/admin/resources/lang/en/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
'permissions.catalogue.orders.description' => 'Allow the staff member to manage orders.',
'permissions.catalogue.customers.name' => 'Manage Customers',
'permissions.catalogue.customers.description' => 'Allow the staff member to manage customers.',
'permissions.discounts.name' => 'Manage Discounts',
'permissions.discounts.description' => 'Allow the staff member to manage discounts',
/**
* Reset password.
*/
Expand Down
15 changes: 15 additions & 0 deletions packages/admin/resources/lang/en/components.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,19 @@
'activity-log.orders.capture' => 'Payment of :amount on card ending :last_four',
'activity-log.orders.authorized' => 'Authorized of :amount on card ending :last_four',
'activity-log.orders.refund' => 'refund of :amount on card ending :last_four',
/**
* Discounts.
*/
'discounts.index.title' => 'Discounts',
'discounts.index.status.pending' => 'Pending',
'discounts.index.status.active' => 'Active',
'discounts.index.status.scheduled' => 'Scheduled',
'discounts.index.status.expired' => 'Expired',
'discounts.index.create_discount' => 'Create Discount',
'discounts.create.title' => 'Create Discount',
'discounts.create_btn' => 'Create Discount',
'discounts.save_btn' => 'Save Discount',
'discounts.show.stop.label' => 'Stop other discounts applying after this one',
'discounts.show.danger_zone.label' => 'Delete discount',
'discounts.show.danger_zone.instructions' => 'Enter the name of the discount to confirm removal.',
];
4 changes: 4 additions & 0 deletions packages/admin/resources/lang/en/global.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@
'brand' => 'Brand',
'stock' => 'Stock',
'show_deleted' => 'Show Deleted',
'starts_at' => 'Starts At',
'ends_at' => 'Ends At',
'priority' => 'Priority',
'stop' => 'Stop',
'preview' => 'Preview',
'delivery_instructions' => 'Delivery Instructions',
'not_provided' => 'Not Provided',
Expand Down
3 changes: 3 additions & 0 deletions packages/admin/resources/lang/en/inputs.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,12 @@
'text' => 'Text',
'richtext' => 'Richtext',
'transaction.label' => 'Transaction',
'starts_at.label' => 'Starts at',
'ends_at.label' => 'Ends at',
'tag.label' => 'Tag',
'active.label' => 'Active',
'priority.label' => 'Priority',
'postcodes.label' => 'Postcodes',
'postcodes.instructions' => 'List each postcode on a new line. Supports wildcards such as NW*',
'max_uses.label' => 'Max uses',
];
1 change: 1 addition & 0 deletions packages/admin/resources/lang/en/menu.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
'sidebar.order-processing' => 'Order Processing',
'sidebar.orders' => 'Orders',
'sidebar.customers' => 'Customers',
'sidebar.discounts' => 'Discounts',
/**
* Product side menu.
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/admin/resources/lang/en/notifications.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
'tax_class.deleted' => 'Tax class deleted',
'clipboard.copied' => 'Copied to clipboard',
'clipboard.failed_copy' => 'Unable to copy to clipboard',
'discount.saved' => 'Discount saved',
'discount.deleted' => 'Discount deleted',
'tags.updated' => 'Tags updated',
'staff.restored' => 'Staff member restored',
'default_url_protected' => 'Unable to delete the default URL',
Expand Down
1 change: 1 addition & 0 deletions packages/admin/resources/lang/en/partials.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
'orders.totals.shipping_total' => 'Shipping Total',
'orders.totals.total' => 'Total',
'orders.totals.notes_empty' => 'No notes on this order',
'orders.totals.discount_total' => 'Discount Total',
'orders.lines.unit_price' => 'Unit Price',
'orders.lines.quantity' => 'Quantity',
'orders.lines.sub_total' => 'Sub Total',
Expand Down
3 changes: 3 additions & 0 deletions packages/admin/resources/lang/en/tables.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
'headings.author' => 'Author',
'headings.products_count' => 'No. Products',
'headings.empty' => 'No Entries Found',
'headings.starts_at' => 'Starts At',
'headings.ends_at' => 'Ends At',
'headings.type' => 'Type',
'headings.tags' => 'Tags',
'headings.new_customer' => 'New Customer',
'headings.new_returning' => 'New/Returning Customers',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
value: @entangle($attributes->wire('model')),
init() {
this.$nextTick(() => {
flatpickr($refs.input, {{ json_encode($options) }})
passedOptions = {{ json_encode($options) }}
options = {
altFormat: passedOptions.enableTime ? 'Y-m-d H:i' : 'Y-m-d',
altInput: true,
}
flatpickr($refs.input, {...options, ...passedOptions})
})
}
}"
@change="value = $event.target.value"
class="flex relative"
wire:ignore
>
<x-hub::input.text
x-ref="input"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<input {{ $attributes }} type="radio" class="w-4 h-4 text-indigo-600 border-gray-300 rounded cursor-pointer hover:bg-gray-50 focus:ring-indigo-500">
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<div>
<div class="grid grid-cols-6 gap-4 p-2 border border-b-0 rounded-t">
<div class="col-span-4">
<x-hub::input.text
wire:model.debounce="searchTerm"
placeholder="Search by collection name"

/>
</div>
<div class="col-span-2">
<x-hub::input.select for="group" wire:model="collectionGroupId" :disabled="!!$this->searchTerm || $showOnlySelected">
@foreach($this->collectionGroups as $group)
<option value="{{ $group->id }}">{{ $group->name }}</option>
@endforeach
</x-hub::input.select>
</div>
</div>
<div class="rounded-b border h-full overflow-y-scroll max-h-96 bg-gray-50">
@if(count($selectedCollections))
<div class="bg-gray-100 py-1 px-2 text-sm border-b text-gray-700">
{{ count($selectedCollections) }} selected,
<a href="#" class="text-blue-600 hover:underline" wire:click.prevent="toggleSelected">
@if($showOnlySelected) show all @endif
@if(!$showOnlySelected) show selected @endif
</a>
</div>
@endif
<div class="px-2">
@foreach($this->collections as $collectionNode)
@include('adminhub::partials.collections.collection-tree-node', [
'node' => $collectionNode,
])
@endforeach
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<div class="space-y-4">
<header>
<h1 class="text-xl font-bold text-gray-900 md:text-2xl dark:text-white">
@if($discount->id)
{{ $discount->name }}
@else
Create Discount
@endif
</h1>
</header>

<form action="#"
method="POST"
wire:submit.prevent="save">
@include('adminhub::partials.forms.discount')
</form>
</div>



{{-- <div class="py-12 pb-24 mt-6">
<div class="sm:px-6 lg:px-0 lg:col-span-9">
<div class="space-y-6">
<div
class="flex-col space-y-4 bg-white rounded px-4 py-5 sm:p-6"
>
<x-hub::input.group for="type" label="Limit discount">
<x-hub::input.select wire:model="discount.restriction">
<option value>All products</option>
<option value="products">Specific products</option>
<option value="collection">Products in collections</option>
</x-hub::input.select>
</x-hub::input.group>
</div>
</div>
</div>
</div> --}}
Loading

0 comments on commit c43f023

Please sign in to comment.