diff --git a/README.md b/README.md
index 8152023..baae813 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
[](https://packagist.org/packages/bumbummen99/shoppingcart)
[](https://packagist.org/packages/bumbummen99/shoppingcart)
-This is a fork of [Crisane's LaravelShoppingcart](https://github.com/Crinsane/LaravelShoppingcart) extended with minor features compatible with Laravel 5.8.
+This is a fork of [Crinsane's LaravelShoppingcart](https://github.com/Crinsane/LaravelShoppingcart) extended with minor features compatible with Laravel 7. An example integration can be [found here](https://github.com/bumbummen99/LaravelShoppingcartDemo).
## Installation
@@ -24,6 +24,7 @@ Now you're ready to start using the shoppingcart in your application.
## Table of Contents
Look at one of the following topics to learn more about LaravelShoppingcart
+* [Important note](#important-note)
* [Usage](#usage)
* [Collections](#collections)
* [Instances](#instances)
@@ -33,6 +34,14 @@ Look at one of the following topics to learn more about LaravelShoppingcart
* [Events](#events)
* [Example](#example)
+## Important note
+
+As all the shopping cart that calculate prices including taxes and discount, also this module could be affected by the "totals rounding issue" ([*](https://stackoverflow.com/questions/13529580/magento-tax-rounding-issue)) due to the decimal precision used for prices and for the results.
+In order to avoid (or at least minimize) this issue, in the Laravel shoppingcart package the totals are calculated using the method **"per Row"** and returned already rounded based on the number format set as default in the config file (cart.php).
+Due to this **WE DISCOURAGE TO SET HIGH PRECISION AS DEFAULT AND TO FORMAT THE OUTPUT RESULT USING LESS DECIMAL** Doing this can lead to the rounding issue.
+
+The base price (product price) is left not rounded.
+
## Usage
The shoppingcart gives you the following methods to use:
@@ -41,16 +50,16 @@ The shoppingcart gives you the following methods to use:
Adding an item to the cart is really simple, you just use the `add()` method, which accepts a variety of parameters.
-In its most basic form you can specify the id, name, quantity, price of the product you'd like to add to the cart.
+In its most basic form you can specify the id, name, quantity, price and weight of the product you'd like to add to the cart.
```php
-Cart::add('293ad', 'Product 1', 1, 9.99);
+Cart::add('293ad', 'Product 1', 1, 9.99, 550);
```
As an optional fifth parameter you can pass it options, so you can add multiple items with the same id, but with (for instance) a different size.
```php
-Cart::add('293ad', 'Product 1', 1, 9.99, 'weight' => 550, ['size' => 'large']);
+Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large']);
```
**The `add()` method will return an CartItem instance of the item you just added to the cart.**
@@ -155,7 +164,7 @@ Cart::destroy();
### Cart::weight()
-The `weight()` method can be used to get the weight total of all items in the cart, given there weight and quantity.
+The `weight()` method can be used to get the weight total of all items in the cart, given their weight and quantity.
```php
Cart::weight();
@@ -245,13 +254,15 @@ You can set the default number format in the config file.
### Cart::initial()
-The `initial()` method can be used to get the total price of all items in the cart before discount.
+The `initial()` method can be used to get the total price of all items in the cart before applying discount and taxes.
+
+It could be deprecated in the future. **When rounded could be affected by the rounding issue**, use it carefully or use [Cart::priceTotal()](#Cart::priceTotal())
```php
Cart::initial();
```
-The method will automatically format the result, which you can tweak using the three optional parameters
+The method will automatically format the result, which you can tweak using the three optional parameters.
```php
Cart::initial($decimals, $decimalSeparator, $thousandSeparator);
@@ -259,6 +270,22 @@ Cart::initial($decimals, $decimalSeparator, $thousandSeparator);
You can set the default number format in the config file.
+### Cart::priceTotal()
+
+The `priceTotal()` method can be used to get the total price of all items in the cart before applying discount and taxes.
+
+```php
+Cart::priceTotal();
+```
+
+The method return the result rounded based on the default number format, but you can tweak using the three optional parameters
+
+```php
+Cart::priceTotal($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+You can set the default number format in the config file.
+
**If you're not using the Facade, but use dependency injection in your (for instance) Controller, you can also simply get the subtotal property `$cart->initial`**
### Cart::count()
@@ -306,8 +333,8 @@ $cart->setTax($rowId, 21);
You can use the `setGlobalTax()` method to change the tax rate for all items in the cart. New items will receive the setGlobalTax as well.
```php
-Cart::setGlobalDiscount(21);
-$cart->setGlobalDiscount(21);
+Cart::setGlobalTax(21);
+$cart->setGlobalTax(21);
```
### Cart::setGlobalDiscount($discountRate)
@@ -315,8 +342,8 @@ $cart->setGlobalDiscount(21);
You can use the `setGlobalDiscount()` method to change the discount rate for all items in the cart. New items will receive the discount as well.
```php
-Cart::setGlobalDiscount(21);
-$cart->setGlobalDiscount(21);
+Cart::setGlobalDiscount(50);
+$cart->setGlobalDiscount(50);
```
### Cart::setDiscount($rowId, $taxRate)
@@ -339,7 +366,7 @@ use Gloudemans\Shoppingcart\Contracts\Buyable;
use Illuminate\Database\Eloquent\Model;
class Product extends Model implements Buyable {
- use Gloudemans\Shoppingcart\CanBeNought;
+ use Gloudemans\Shoppingcart\CanBeBought;
}
```
@@ -540,10 +567,18 @@ If you want to retrieve the cart from the database and restore it, all you have
Cart::instance('wishlist')->restore('username');
### Merge the cart
-If you want to merge the cart with another one from the database, all you have to do is call the `merge($identifier)` where `$identifier` is the key you specified for the `store` method. You can also define if you want to keep the discount and tax rates of the items.
+If you want to merge the cart with another one from the database, all you have to do is call the `merge($identifier)` where `$identifier` is the key you specified for the `store` method. You can also define if you want to keep the discount and tax rates of the items and if you want to dispatch "cart.added" events.
// Merge the contents of 'savedcart' into 'username'.
- Cart::instance('username')->merge('savedcart', $keepDiscount, $keepTaxrate);
+ Cart::instance('username')->merge('savedcart', $keepDiscount, $keepTaxrate, $dispatchAdd);
+
+### Erasing the cart
+If you want to erase the cart from the database, all you have to do is call the `erase($identifier)` where `$identifier` is the key you specified for the `store` method.
+
+ Cart::erase('username');
+
+ // To erase a cart switching to an instance named 'wishlist'
+ Cart::instance('wishlist')->erase('username');
## Exceptions
@@ -564,8 +599,10 @@ The cart also has events build in. There are five events available for you to li
| cart.added | When an item was added to the cart. | The `CartItem` that was added. |
| cart.updated | When an item in the cart was updated. | The `CartItem` that was updated. |
| cart.removed | When an item is removed from the cart. | The `CartItem` that was removed. |
+| cart.merged | When the content of a cart is merged | - |
| cart.stored | When the content of a cart was stored. | - |
| cart.restored | When the content of a cart was restored. | - |
+| cart.erased | When the content of a cart was erased. | - |
## Example
diff --git a/README_Idn.md b/README_Idn.md
new file mode 100644
index 0000000..3839008
--- /dev/null
+++ b/README_Idn.md
@@ -0,0 +1,628 @@
+## LaravelShoppingcart
+[](https://travis-ci.org/bumbummen99/LaravelShoppingcart)
+[](https://codecov.io/gh/bumbummen99/LaravelShoppingcart)
+[](https://styleci.io/repos/152610878)
+[](https://packagist.org/packages/bumbummen99/shoppingcart)
+[](https://packagist.org/packages/bumbummen99/shoppingcart)
+[](https://packagist.org/packages/bumbummen99/shoppingcart)
+[](https://packagist.org/packages/bumbummen99/shoppingcart)
+
+Ini adalah percabangan dari [Crinsane's LaravelShoppingcart](https://github.com/Crinsane/LaravelShoppingcart) dikembangkan dengan fitur-fitur minor yang kompatibel dengan Laravel 6
+
+## Instalasi
+
+Install paket(https://packagist.org/packages/bumbummen99/shoppingcart) menggunakan [Composer](http://getcomposer.org/).
+
+Jalankan Composer dengan menggunakan perintah berikut:
+
+ composer require bumbummen99/shoppingcart
+
+Sekarang Anda siap untuk mulai menggunakan shoppingcart di aplikasi Anda.
+
+**Pada versi 2 dari paket ini memungkinkan untuk menggunakan injeksi dependensi untuk memasukkan instance Class Cart ke controller Anda atau Class lain**
+
+## Gambaran
+Lihat salah satu topik berikut untuk mempelajari lebih lanjut tentang LaravelShoppingcart
+
+* [Usage](#usage)
+* [Collections](#collections)
+* [Instances](#instances)
+* [Models](#models)
+* [Database](#database)
+* [Exceptions](#exceptions)
+* [Events](#events)
+* [Example](#example)
+
+## Penggunaan
+
+Shoppingcart memberi Anda metode berikut untuk digunakan:
+
+### Cart::add()
+
+Menambahkan item ke troli sangat sederhana, Anda cukup menggunakan metode `add ()`, yang menerima berbagai parameter.
+
+Dalam bentuknya yang paling mendasar, Anda dapat menentukan id, nama, jumlah, harga, dan berat produk yang ingin Anda tambahkan ke troli.
+
+```php
+Cart::add('293ad', 'Product 1', 1, 9.99, 550);
+```
+
+Sebagai opsional parameter kelima, Anda dapat memberikan opsi, sehingga Anda dapat menambahkan beberapa item dengan id yang sama, tetapi dengan (instance) ukuran yang berbeda.
+
+```php
+Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large']);
+```
+
+**Metode `add ()` akan mengembalikan instance CartItem dari item yang baru saja Anda tambahkan ke troli.**
+
+Mungkin Anda lebih suka menambahkan item menggunakan array? Selama array berisi kunci yang diperlukan, Anda bisa meneruskannya ke metode. Tombol opsi adalah opsional.
+
+```php
+Cart::add(['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 9.99, 'weight' => 550, 'options' => ['size' => 'large']]);
+```
+
+Baru dalam versi 2 paket ini adalah kemungkinan untuk bekerja dengan antarmuka [Buyable] (#buyable). Cara kerjanya adalah bahwa Anda memiliki model yang mengimplementasikan antarmuka [Buyable] (#buyable), yang akan membuat Anda menerapkan beberapa metode sehingga paket tahu bagaimana cara mendapatkan id, nama, dan harga dari model Anda.
+Dengan cara ini Anda bisa meneruskan metode `add ()` model dan kuantitas dan secara otomatis akan menambahkannya ke troli.
+
+**Sebagai bonus tambahan, itu akan secara otomatis mengaitkan model dengan CartItem**
+
+```php
+Cart::add($product, 1, ['size' => 'large']);
+```
+Sebagai parameter ketiga opsional, Anda dapat menambahkan opsi.
+```php
+Cart::add($product, 1, ['size' => 'large']);
+```
+
+Terakhir, Anda juga dapat menambahkan banyak item ke troli sekaligus.
+Anda bisa meneruskan metode `add ()` sebuah array array, atau array yang dapat dibeli dan mereka akan ditambahkan ke troli.
+
+**Saat menambahkan beberapa item ke troli, metode `add ()` akan mengembalikan array CartItems.**
+
+```php
+Cart::add([
+ ['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 10.00, 'weight' => 550],
+ ['id' => '4832k', 'name' => 'Product 2', 'qty' => 1, 'price' => 10.00, 'weight' => 550, 'options' => ['size' => 'large']]
+]);
+
+Cart::add([$product1, $product2]);
+
+```
+
+### Cart::update()
+
+Untuk memperbarui item di troli, Anda harus terlebih dahulu membutuhkan rowId item.
+Selanjutnya Anda dapat menggunakan metode `update ()` untuk memperbaruinya.
+
+Jika Anda hanya ingin memperbarui kuantitas, Anda akan melewati metode pembaruan rowId dan kuantitas baru:
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::update($rowId, 2); // Will update the quantity
+```
+Jika Anda ingin memperbarui lebih banyak atribut dari item, Anda dapat melewati metode pembaruan array atau `Dapat Dibeli` sebagai parameter kedua. Dengan cara ini Anda dapat memperbarui semua informasi item dengan rowId yang diberikan.
+
+```php
+Cart::update($rowId, ['name' => 'Product 1']); // Will update the name
+
+Cart::update($rowId, $product); // Will update the id, name and price
+
+```
+
+### Cart::remove()
+
+Untuk menghapus item untuk keranjang, Anda akan membutuhkan rowId lagi. Baris ini. Apakah Anda hanya meneruskan ke metode `hapus ()` dan itu akan menghapus item dari keranjang.
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::remove($rowId);
+```
+
+### Cart::get()
+
+Jika Anda ingin mendapatkan item dari troli menggunakan rowId-nya, Anda bisa memanggil metode `get ()` di troli dan meneruskannya dengan rowId.
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::get($rowId);
+```
+
+### Cart::content()
+
+Tentu saja Anda juga ingin mendapatkan konten gerobak. Di sinilah Anda akan menggunakan metode `konten`. Metode ini akan mengembalikan Koleksi CartItems yang dapat Anda ulangi dan tampilkan kontennya kepada pelanggan Anda.
+
+```php
+Cart::content();
+```
+Metode ini akan mengembalikan konten instance keranjang saat ini, jika Anda ingin konten instance lain, cukup lakukan panggilan.
+
+```php
+Cart::instance('wishlist')->content();
+```
+
+### Cart::destroy()
+
+Jika Anda ingin menghapus konten keranjang sepenuhnya, Anda dapat memanggil metode penghancuran di kereta. Ini akan menghapus semua CartItems dari troli untuk instance troli saat ini.
+
+```php
+Cart::destroy();
+```
+
+### Cart::weight()
+
+Metode `weight ()` dapat digunakan untuk mendapatkan total berat semua item di troli, mengingat berat dan kuantitasnya.
+
+
+```php
+Cart::weight();
+```
+
+Metode ini akan memformat hasilnya secara otomatis, yang dapat Anda atur menggunakan tiga parameter opsional
+
+```php
+Cart::weight($decimals, $decimalSeperator, $thousandSeperator);
+```
+
+Anda dapat mengatur format angka default dalam file konfigurasi.
+
+**Jika Anda tidak menggunakan Facade, tetapi menggunakan injeksi ketergantungan pada Pengontrol Anda (misalnya), Anda juga bisa mendapatkan total properti `$ cart-> weight`**
+
+### Cart::total()
+
+Maka `total ()` dapat digunakan untuk mendapatkan total yang dihitung dari semua item dalam troli, mengingat ada harga dan kuantitas.
+
+```php
+Cart::total();
+```
+
+Metode ini akan memformat hasilnya secara otomatis, yang dapat Anda atur menggunakan tiga parameter opsional
+
+```php
+Cart::total($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Anda dapat mengatur format angka default dalam file konfigurasi.
+
+
+**Jika Anda tidak menggunakan Facade, tetapi menggunakan injeksi ketergantungan pada Pengontrol Anda (misalnya), Anda juga bisa mendapatkan total properti `$ cart-> total`**
+
+### Cart::tax()
+
+Maka `tax ()` dapat digunakan untuk mendapatkan jumlah pajak yang dihitung untuk semua item di troli, mengingat ada harga dan kuantitas.
+
+```php
+Cart::tax();
+```
+
+Metode ini akan memformat hasilnya secara otomatis, yang dapat Anda atur menggunakan tiga parameter opsional
+
+```php
+Cart::tax($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Anda dapat mengatur format angka default dalam file konfigurasi.
+
+**Jika Anda tidak menggunakan Facade, tetapi menggunakan injeksi ketergantungan pada Pengontrol Anda (misalnya), Anda juga bisa mendapatkan total properti `$ cart-> tax`**
+
+### Cart::subtotal()
+
+Maka `subtotal ()` dapat digunakan untuk mendapatkan total semua item dalam troli, dikurangi jumlah total pajak.
+
+```php
+Cart::subtotal();
+```
+
+Metode ini akan memformat hasilnya secara otomatis, yang dapat Anda atur menggunakan tiga parameter opsional
+
+```php
+Cart::subtotal($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Anda dapat mengatur format angka default dalam file konfigurasi.
+
+**Jika Anda tidak menggunakan Facade, tetapi menggunakan injeksi ketergantungan pada Pengontrol Anda (misalnya), Anda juga bisa mendapatkan total properti `$ cart-> subtotal`**
+
+### Cart::discount()
+
+Maka `diskon ()` dapat digunakan untuk mendapatkan diskon total semua item di troli.
+
+```php
+Cart::discount();
+```
+
+Metode ini akan memformat hasilnya secara otomatis, yang dapat Anda atur menggunakan tiga parameter opsional
+
+```php
+Cart::discount($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Anda dapat mengatur format angka default dalam file konfigurasi.
+
+**Jika Anda tidak menggunakan Facade, tetapi menggunakan injeksi ketergantungan pada Pengontrol Anda (misalnya), Anda juga bisa mendapatkan total properti `$ cart-> discount`**
+
+### Cart::initial()
+
+maka `initial ()` dapat digunakan untuk mendapatkan harga total semua item di troli sebelum diskon.
+
+```php
+Cart::initial();
+```
+
+Metode ini akan memformat hasilnya secara otomatis, yang dapat Anda atur menggunakan tiga parameter opsional
+
+```php
+Cart::initial($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Anda dapat mengatur format angka default dalam file konfigurasi.
+
+**Jika Anda tidak menggunakan Facade, tetapi menggunakan injeksi ketergantungan pada Pengontrol Anda (misalnya), Anda juga bisa mendapatkan total properti `$ cart-> initial`**
+
+### Cart::count()
+
+Jika Anda ingin tahu berapa banyak item yang ada di troli Anda, Anda dapat menggunakan metode `count ()`. Metode ini akan mengembalikan jumlah total barang dalam kereta. Jadi, jika Anda telah menambahkan 2 buku dan 1 kemeja, itu akan mengembalikan 3 item.
+
+```php
+Cart::count();
+$cart->count();
+```
+
+### Cart::search()
+
+Untuk menemukan item di troli, Anda dapat menggunakan metode `search ()`.
+
+**Metode ini diubah pada versi 2**
+
+Di belakang layar, metode ini hanya menggunakan metode filter dari kelas Laravel Collection. Ini berarti Anda harus memberikannya suatu Penutupan di mana Anda akan menentukan istilah pencarian Anda.
+
+Jika Anda misalnya ingin menemukan semua item dengan id 1:
+
+```php
+$cart->search(function ($cartItem, $rowId) {
+ return $cartItem->id === 1;
+});
+```
+
+Seperti yang Anda lihat, Penutupan akan menerima dua parameter. Yang pertama adalah Item Keranjang untuk melakukan pemeriksaan terhadap. Parameter kedua adalah rowId dari CartItem ini.
+
+** Metode ini akan mengembalikan Koleksi yang berisi semua CartItems yang ditemukan **
+
+Cara pencarian ini memberi Anda kontrol total atas proses pencarian dan memberi Anda kemampuan untuk membuat pencarian yang sangat tepat dan spesifik.
+
+### Cart :: setTax ($ rowId, $ taxRate)
+
+Anda dapat menggunakan metode `setTax ()` untuk mengubah tarif pajak yang berlaku untuk CartItem. Ini akan menimpa nilai yang ditetapkan dalam file konfigurasi.
+
+```php
+Cart::setTax($rowId, 21);
+$cart->setTax($rowId, 21);
+```
+
+### Cart::setGlobalTax($taxRate)
+
+Anda dapat menggunakan metode `setGlobalTax ()` untuk mengubah tarif pajak untuk semua item di troli. Item baru juga akan menerima setGlobalTax.
+
+```php
+Cart::setGlobalTax(21);
+$cart->setGlobalTax(21);
+```
+
+### Cart::setGlobalDiscount($discountRate)
+
+Anda dapat menggunakan metode `setGlobalDiscount ()` untuk mengubah tingkat diskonto untuk semua item di troli. Barang baru akan menerima diskon juga.
+
+```php
+Cart::setGlobalDiscount(50);
+$cart->setGlobalDiscount(50);
+```
+
+### Cart::setDiscount($rowId, $taxRate)
+
+Anda dapat menggunakan metode `setDiscount ()` untuk mengubah tingkat diskonto yang menerapkan CartItem. Perlu diingat bahwa nilai ini akan berubah jika Anda menetapkan diskon global untuk Keranjang sesudahnya.
+
+```php
+Cart::setDiscount($rowId, 21);
+$cart->setDiscount($rowId, 21);
+```
+
+### Buyable
+
+Untuk kenyamanan menambahkan item yang lebih cepat ke troli dan asosiasi otomatisnya, model Anda harus mengimplementasikan antarmuka `Dapat Dibeli` Anda dapat menggunakan sifat `CanBeBought` untuk mengimplementasikan metode yang diperlukan tetapi perlu diingat bahwa ini akan menggunakan bidang yang telah ditentukan pada model Anda untuk nilai yang diperlukan.
+
+```php
+id;
+ }
+ public function getBuyableDescription(){
+ return $this->name;
+ }
+ public function getBuyablePrice(){
+ return $this->price;
+ }
+ public function getBuyableWeight(){
+ return $this->weight;
+ }
+```
+
+Contoh:
+
+```php
+id;
+ }
+ public function getBuyableDescription($options = null) {
+ return $this->name;
+ }
+ public function getBuyablePrice($options = null) {
+ return $this->price;
+ }
+}
+```
+
+## Collections
+
+Dalam beberapa kasus, Keranjang akan mengembalikan kepada Anda Koleksi. Ini hanya Koleksi Laravel sederhana, sehingga semua metode yang dapat Anda panggil pada Koleksi Laravel juga tersedia pada hasilnya.
+
+Sebagai contoh, Anda dapat dengan cepat mendapatkan jumlah produk unik dalam keranjang:
+
+```php
+Cart::content()->count();
+```
+
+Atau Anda dapat mengelompokkan konten berdasarkan id produk:
+
+```php
+Cart::content()->groupBy('id');
+```
+
+## Instances
+
+Paket-paket mendukung beberapa instance dari kereta. Cara kerjanya seperti ini:
+
+Anda dapat mengatur instance keranjang saat ini dengan memanggil `Cart :: instance ('newInstance')`. Mulai saat ini, instance aktif dari cart adalah `newInstance`, jadi ketika Anda menambah, menghapus, atau mendapatkan konten dari cart, Anda bekerja dengan instance` newInstance` dari cart.
+Jika Anda ingin mengganti instance, Anda cukup memanggil `Cart :: instance ('otherInstance')` lagi, dan Anda bekerja dengan `otherInstance` lagi.
+
+Contoh Kecil:
+
+```php
+Cart::instance('shopping')->add('192ao12', 'Product 1', 1, 9.99, 550);
+
+// Get the content of the 'shopping' cart
+Cart::content();
+
+Cart::instance('wishlist')->add('sdjk922', 'Product 2', 1, 19.95, 550, ['size' => 'medium']);
+
+// Get the content of the 'wishlist' cart
+Cart::content();
+
+// If you want to get the content of the 'shopping' cart again
+Cart::instance('shopping')->content();
+
+// And the count of the 'wishlist' cart again
+Cart::instance('wishlist')->count();
+```
+
+Anda juga dapat menggunakan Kontrak `InstanceIdentifier` untuk memperpanjang Model yang diinginkan untuk menetapkan / membuat instance Cart untuknya. Ini juga memungkinkan untuk secara langsung mengatur diskon global.
+```
+email;
+ }
+
+ /**
+ * Get the unique identifier to load the Cart from
+ *
+ * @return int|string
+ */
+ public function getInstanceGlobalDiscount($options = null)
+ {
+ return $this->discountRate ?: 0;
+ }
+}
+
+// Inside Controller
+$user = \Auth::user();
+$cart = Cart::instance($user);
+
+
+
+```
+
+**N.B. Ingatlah bahwa troli tetap berada di set instance terakhir selama Anda tidak menyetel yang berbeda selama eksekusi skrip.**
+
+**N.B.2 Contoh cart default disebut `default`, jadi ketika Anda tidak menggunakan instance,` Cart :: konten (); `sama dengan` Cart :: instance ('default') -> konten () `.**
+
+## Models
+
+Karena sangat nyaman untuk dapat secara langsung mengakses model dari CartItem, apakah mungkin untuk mengaitkan model dengan barang-barang di dalam kereta. Katakanlah Anda memiliki model `Produk` di aplikasi Anda. Dengan metode `associate ()`, Anda dapat memberi tahu troli bahwa item di troli, terkait dengan model `Product`.
+
+Dengan begitu Anda dapat mengakses model Anda langsung dari `CartItem`!
+
+Model ini dapat diakses melalui properti `model` di CartItem.
+
+**Jika model Anda mengimplementasikan antarmuka `Buy Able` dan Anda menggunakan model Anda untuk menambahkan item ke troli, itu akan dikaitkan secara otomatis.**
+
+Berikut adalah contoh:
+
+```php
+
+// First we'll add the item to the cart.
+$cartItem = Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large']);
+
+// Next we associate a model with the item.
+Cart::associate($cartItem->rowId, 'Product');
+
+// Or even easier, call the associate method on the CartItem!
+$cartItem->associate('Product');
+
+// You can even make it a one-liner
+Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large'])->associate('Product');
+
+// Now, when iterating over the content of the cart, you can access the model.
+foreach(Cart::content() as $row) {
+ echo 'You have ' . $row->qty . ' items of ' . $row->model->name . ' with description: "' . $row->model->description . '" in your cart.';
+}
+```
+## Database
+
+- [Config](#configuration)
+- [Storing the cart](#storing-the-cart)
+- [Restoring the cart](#restoring-the-cart)
+
+### Konfigurasi
+Untuk menyimpan keranjang ke dalam basis data sehingga Anda dapat mengambilnya nanti, paket perlu mengetahui koneksi basis data yang digunakan dan apa nama tabelnya.
+Secara default paket akan menggunakan koneksi database default dan menggunakan tabel bernama `shoppingcart`.
+Jika Anda ingin mengubah opsi ini, Anda harus menerbitkan file `config`.
+
+ php artisan vendor:publish --provider="Gloudemans\Shoppingcart\ShoppingcartServiceProvider" --tag="config"
+
+Ini akan memberi Anda file konfigurasi `cart.php` di mana Anda dapat melakukan perubahan.
+
+Untuk memudahkan hidup Anda, paket ini juga menyertakan `migration` yang siap digunakan yang dapat Anda terbitkan dengan menjalankan:
+
+ php artisan vendor:publish --provider="Gloudemans\Shoppingcart\ShoppingcartServiceProvider" --tag="migrations"
+
+Ini akan menempatkan file migrasi tabel `shoppingcart` ke direktori` database / migrations`. Sekarang yang harus Anda lakukan adalah menjalankan `php artisan migrate` untuk memigrasi basis data Anda.
+
+### Menyimpan ke Troli
+Untuk menyimpan instance kereta ke dalam database, Anda harus memanggil metode `store ($ identifier)`. Di mana `$ identifier` adalah kunci acak, misalnya id atau nama pengguna pengguna.
+
+ Cart::store('username');
+
+ // To store a cart instance named 'wishlist'
+ Cart::instance('wishlist')->store('username');
+
+### Mengembalikan ke Troli
+Jika Anda ingin mengambil keranjang dari database dan mengembalikannya, yang harus Anda lakukan adalah memanggil `restore ($ identifier)` di mana `$ identifier` adalah kunci yang Anda tentukan untuk metode` store`.
+
+ Cart::restore('username');
+
+ // To restore a cart instance named 'wishlist'
+ Cart::instance('wishlist')->restore('username');
+
+### Menggabungkan Troli
+Jika Anda ingin menggabungkan keranjang dengan keranjang lain dari basis data, yang harus Anda lakukan adalah memanggil `gabungan ($ identifier)` di mana `$ identifier` adalah kunci yang Anda tentukan untuk metode` store`. Anda juga dapat menentukan apakah Anda ingin mempertahankan potongan harga dan tarif pajak item.
+
+ // Merge the contents of 'savedcart' into 'username'.
+ Cart::instance('username')->merge('savedcart', $keepDiscount, $keepTaxrate);
+
+## Pengecualian
+
+Paket Cart akan mengeluarkan pengecualian jika terjadi kesalahan. Dengan cara ini lebih mudah untuk men-debug kode Anda menggunakan paket Cart atau untuk menangani kesalahan berdasarkan pada jenis pengecualian. Paket-paket Cart dapat membuang pengecualian berikut:
+
+| Exception | Reason |
+| ---------------------------- | ---------------------------------------------------------------------------------- |
+| *CartAlreadyStoredException* | Saat mencoba menyimpan keranjang yang sudah disimpan menggunakan pengenal yang ditentukan |
+| *InvalidRowIDException* | Ketika rowId yang diteruskan tidak ada dalam instance troli saat ini |
+| *UnknownModelException* | Saat Anda mencoba mengaitkan model yang tidak ada dengan Item Keranjang. |
+
+## Events
+
+Troli juga memiliki event. Ada lima event yang bisa Anda lakukan.
+
+| Event | Fired | Parameter |
+| ------------- | ---------------------------------------- | -------------------------------- |
+| cart.added | Saat item ditambahkan ke troli. | The `CartItem` that was added. |
+| cart.updated | Ketika item dalam troli diperbarui. | The `CartItem` that was updated. |
+| cart.removed | Ketika item dalam troli dihapus. | The `CartItem` that was removed. |
+| cart.stored | Ketika isi trol disimpan. | - |
+| cart.restored | Ketika konten keranjang Dikembalikan. | - |
+
+## Contoh
+
+Di bawah ini adalah sedikit contoh cara membuat daftar isi keranjang dalam sebuah tabel:
+
+```php
+
+// Tambahkan beberapa item di Kontroler Anda.
+Cart::add('192ao12', 'Product 1', 1, 9.99);
+Cart::add('1239ad0', 'Product 2', 2, 5.95, ['size' => 'large']);
+
+// Tampilkan konten dalam Tampilan.
+
+```
diff --git a/README_uk-UA.md b/README_uk-UA.md
new file mode 100644
index 0000000..af44477
--- /dev/null
+++ b/README_uk-UA.md
@@ -0,0 +1,626 @@
+## LaravelShoppingcart
+[](https://travis-ci.org/bumbummen99/LaravelShoppingcart)
+[](https://codecov.io/gh/bumbummen99/LaravelShoppingcart)
+[](https://styleci.io/repos/152610878)
+[](https://packagist.org/packages/bumbummen99/shoppingcart)
+[](https://packagist.org/packages/bumbummen99/shoppingcart)
+[](https://packagist.org/packages/bumbummen99/shoppingcart)
+[](https://packagist.org/packages/bumbummen99/shoppingcart)
+
+Цей репозиторій є відгалуженням [Crinsane's LaravelShoppingcart](https://github.com/Crinsane/LaravelShoppingcart) та містить додаткові незначні доповнення, сумісні з Laravel 6.
+
+## Встановлення
+
+Встановіть [пакет](https://packagist.org/packages/bumbummen99/shoppingcart) скориставшись [Завантажувачем](http://getcomposer.org/).
+
+Для запуску Завантажувача, скористайтеся командою у Терміналі:
+
+ composer require bumbummen99/shoppingcart
+
+Тепер ви готові розпочати користуватися кошиком у вашому застосунку.
+
+**Починаючи з версії 2 даного пакету з'явилася можливість впровадження залежності для впровадження екземпляра класу Кошик (Cart) до вашого контролера або іншого класу**
+
+## Огляд
+Щоб детальніше ознайомитися LaravelShoppingcart, можете пройти за посиланнями
+
+* [Застосування](#usage)
+* [Колекції](#collections)
+* [Екземпляри](#instances)
+* [Моделі](#models)
+* [База даних](#database)
+* [Винятки](#exceptions)
+* [Події](#events)
+* [Приклад](#example)
+
+## Застосування
+
+Кошик (Cart) дозволяє вам скористатися наступними методами:
+
+### Cart::add()
+
+Додавати покупки у кошик дуже зручно - достатньо скористатися методом `add()`, який приймає різноманітні параметри.
+
+У найпростішій формі метода достатньо вказати ідентифікатор товару, назву, кількість, ціну та вагу товару, який ви хочете додати у кошик.
+
+```php
+Cart::add('293ad', 'Product 1', 1, 9.99, 550);
+```
+
+У якості додаткового п'ятого параметра можна задати додаткові опції, наприклад, щоб додати декілька одиниць з однаковим ідентифікатором, але, наприклад, різного розміру.
+
+```php
+Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large']);
+```
+
+**Метод `add()` повертає екземпляр CartItems того товару, який ви щойно додали у кошик.**
+
+Можливо, вам більше до вподоби додавати товари, використовуючи масив? Якщо масив містить усі необхідні поля, ви можете передавати масив у цей метод. Поле із додатковими опціями є необов'язковим.
+
+```php
+Cart::add(['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 9.99, 'weight' => 550, 'options' => ['size' => 'large']]);
+```
+
+У версії 2 пакета з'явилася нова можливість для роботи з інтерфейсом [Buyable](#buyable). Такий функціонал з'являється за рахунок того, що модель запускає інтерфейс [Buyable](#buyable), який дозволить імплементувати декілька методів, з яких пакет знатиме як отримати ідентифікатор, назву та ціну з вашої моделі.
+Таким чином, ви можете передати метод `add()` та кількість одиниць товару до моделі, а вона автоматично додасть їх до кошика.
+
+**Додатковий бонус інтерфейсу - автоматичне об'єднання моделі з CartItems**
+
+```php
+Cart::add($product, 1, ['size' => 'large']);
+```
+У якості додаткового параметра, ви можете внести опції.
+```php
+Cart::add($product, 1, ['size' => 'large']);
+```
+
+Нарешті, ви також можете додавати до кошика декілька одиниць водночас. Для цього потрібно передати у `add()` масив масивів або масив Buyables, і їх буде додано в кошик.
+
+**Під час додавання декількох одиниць товару в кошик, метод `add()` повертає масив CartItems.**
+
+```php
+Cart::add([
+ ['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 10.00, 'weight' => 550],
+ ['id' => '4832k', 'name' => 'Product 2', 'qty' => 1, 'price' => 10.00, 'weight' => 550, 'options' => ['size' => 'large']]
+]);
+
+Cart::add([$product1, $product2]);
+
+```
+
+### Cart::update()
+
+Щоб оновити товар у кошику, вам знадобиться ідентифікатор рядка (rowId) даного товару.
+Далі ви можете скористатися методом `update()` для того, щоб оновити його.
+
+Якщо ви просто хочете оновити кількість товару, вам необхідно передати у метод `update()` rowId і оновлену кількість:
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::update($rowId, 2); // Will update the quantity
+```
+
+Якщо ви хочете оновити більше атрибутів товару, вам потрібно або передати у метод `update()` масив або `Buyable` у якості другого параметра. Таким чином, ви можете оновити всю інформацію про товар за заданим rowId.
+
+```php
+Cart::update($rowId, ['name' => 'Product 1']); // Will update the name
+
+Cart::update($rowId, $product); // Will update the id, name and price
+
+```
+
+### Cart::remove()
+
+Щоб вилучити товар з кошика, вам знову знадобиться rowId. Такий rowId потрібно передати у метод `remove()`, який автоматично вилучить товар із кошика.
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::remove($rowId);
+```
+
+### Cart::get()
+
+Якщо ви хочете отримати товар із кошика, використовуючи його rowId, вам потрібно застосувати метод `get()` щодо кошика і передати в нього rowId.
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::get($rowId);
+```
+
+### Cart::content()
+
+Вам також може знадобитися можливість отримати інформацію про вміст кошика. Для цього вам потрібно скористатися методом `content`. Такий метод повертає колекцію CartItems, ви можете перебирати вміст такої колекції і відобразити вміст кошика для ваших клієнтів.
+
+```php
+Cart::content();
+```
+
+Даний метод повертає вміст поточного екземпляра кошика, якщо ви хочете вміст іншого екземпляра, вам потрібно зв'язати виклики.
+
+```php
+Cart::instance('wishlist')->content();
+```
+
+### Cart::destroy()
+
+Якщо ви хочете остаточно вилучити вміст кошика, ви можете застосувати метод `destroy()` щодо кошика. Даний метод вилучить всі CartItems з кошика для поточного екземпляра кошика.
+
+```php
+Cart::destroy();
+```
+
+### Cart::weight()
+
+Метод `weight()` можна застосувати, щоб отримати розрахунок ваги усіх товарів у кошику, за умови, що задано вагу і кількість одиниць.
+
+```php
+Cart::weight();
+```
+
+Даний метод автоматично відформатує результат, який ви можете поправити за допомогою трьох додаткових параметрів.
+
+```php
+Cart::weight($decimals, $decimalSeperator, $thousandSeperator);
+```
+
+Ви можете задати формат чисел за замовчуванням у файлі з конфігураціями.
+
+**Якщо ви не використовуєте Фасад, але застосовуєте впровадження залежності, наприклад, у вашому Контролері, ви також можете отримати інформацію про вагу товарів через `$cart->weight`**
+
+### Cart::total()
+
+Метод `total()` можна застосовувати, щоб отримати розрахунок вартості усіх товарів у кошику, за умови, що задані ціна і кількість одиниць.
+
+```php
+Cart::total();
+```
+
+Даний метод автоматично відформатує результат, який ви можете поправити за допомогою трьох додаткових параметрів.
+
+```php
+Cart::total($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Ви можете задати формат чисел за замовчуванням у файлі з конфігураціями.
+
+**Якщо ви не використовуєте Фасад, але застосовуєте впровадження залежності, наприклад, у вашому Контролері, ви також можете отримати інформацію про вартість товарів через `$cart->total`**
+
+### Cart::tax()
+
+Метод `tax()` можна застосовувати, щоб отримати розрахунок суми податків для усіх товарів у кошику, за умови, що задані ціна і кількість одиниць.
+
+```php
+Cart::tax();
+```
+
+Даний метод автоматично відформатує результат, який ви можете поправити за допомогою трьох додаткових параметрів.
+
+```php
+Cart::tax($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Ви можете задати формат чисел за замовчуванням у файлі з конфігураціями.
+
+**Якщо ви не використовуєте Фасад, але застосовуєте впровадження залежності, наприклад, у вашому Контролері, ви також можете отримати інформацію про суму податку на товари через `$cart->tax`**
+
+### Cart::subtotal()
+
+Метод `subtotal()` можна застосовувати, щоб отримати розрахунок вартості усіх товарів у кошику, без урахування суми податку.
+
+```php
+Cart::subtotal();
+```
+
+Даний метод автоматично відформатує результат, який ви можете поправити за допомогою трьох додаткових параметрів.
+
+```php
+Cart::subtotal($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Ви можете задати формат чисел за замовчуванням у файлі з конфігураціями.
+
+**Якщо ви не використовуєте Фасад, але застосовуєте впровадження залежності, наприклад, у вашому Контролері, ви також можете отримати інформацію про вартість усіх товарів без урахування суми податків через `$cart->subtotal`**
+
+### Cart::discount()
+
+Метод `discount()` можна застосовувати, щоб отримати розрахунок знижки на усі товари у кошику.
+
+```php
+Cart::discount();
+```
+
+Даний метод автоматично відформатує результат, який ви можете поправити за допомогою трьох додаткових параметрів.
+
+```php
+Cart::discount($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Ви можете задати формат чисел за замовчуванням у файлі з конфігураціями.
+
+**Якщо ви не використовуєте Фасад, але застосовуєте впровадження залежності, наприклад, у вашому Контролері, ви також можете отримати інформацію про вартість усіх товарів з урахуванням знижки `$cart->discount`**
+
+### Cart::initial()
+
+Метод `initial()` можна застосовувати, щоб отримати розрахунок вартості усіх товарів до застосування знижки.
+
+```php
+Cart::initial();
+```
+
+Даний метод автоматично відформатує результат, який ви можете поправити за допомогою трьох додаткових параметрів.
+
+```php
+Cart::initial($decimals, $decimalSeparator, $thousandSeparator);
+```
+
+Ви можете задати формат чисел за замовчуванням у файлі з конфігураціями.
+
+**Якщо ви не використовуєте Фасад, але застосовуєте впровадження залежності, наприклад, у вашому Контролері, ви також можете отримати інформацію про вартість усіх товарів до застосування знижки `$cart->initial`**
+
+### Cart::count()
+
+Метод `count()` можна застосовувати, щоб дізнатися кількість одиниць товарів у кошику. Даний метод повертає загальну кількість одиниць товарів у кошику. Тобто якщо ви додали 2 книжки і 1 сорочку, цей метод поверне 3 одиниці.
+
+```php
+Cart::count();
+$cart->count();
+```
+
+### Cart::search()
+
+Метод `search()` можна застосовувати, щоб знайти одиницю товару у кошику.
+
+**Даний метод було змінено у версії 2**
+
+У своїй імплементації, цей метод застосовує метод фільтрування з класу Laravel Collection. Це означає, що вам потрібно передати замикання (Closure) для даного методу, де ви зазначите умови для пошуку.
+
+Наприклад, якщо ви хочете знайти всі одиниці товару з ідентифікатором 1:
+
+```php
+$cart->search(function ($cartItem, $rowId) {
+ return $cartItem->id === 1;
+});
+```
+
+Як ви можете побачити, замикання отримає 2 параметра. Перший - CartItem для здійснення перевірки щодо нього. Другий параметр - rowId даного CartItem.
+
+**Даний метод повертає колекцію, яка вміщує всі CartItems, які було знайдено**
+
+Такий спосіб пошуку надає вам повний контроль над процесом пошуку та дозволяє здійснювати дуже точні та конкретні пошуки.
+
+### Cart::setTax($rowId, $taxRate)
+
+Метод `setTax()` можна застосовувати, щоб змінювати ставку оподаткування, яка застосовується до CartItem. Така операція перезапише значення встановлене у файлі з конфігураціями.
+
+```php
+Cart::setTax($rowId, 21);
+$cart->setTax($rowId, 21);
+```
+
+### Cart::setGlobalTax($taxRate)
+
+Метод `setGlobalTax()` можна застосовувати, щоб змінити ставку оподаткування для усіх найменувать у кошику. Нові найменування отримають значення setGlobalTax також.
+
+```php
+Cart::setGlobalTax(21);
+$cart->setGlobalTax(21);
+```
+
+### Cart::setGlobalDiscount($discountRate)
+
+Метод `setGlobalDiscount()` можна застосовувати для заміни ставки знижки щодо усіх найменувань у кошику. Нові найменування також отримуватимуть таку знижку.
+
+```php
+Cart::setGlobalDiscount(50);
+$cart->setGlobalDiscount(50);
+```
+
+### Cart::setDiscount($rowId, $taxRate)
+
+Застосування методу `setDiscount()` полягає у заміні ставки знижки, яка застосовується до CartItem. Зверніть увагу, що дане значення ставки знижки буде змінено, якщо ви згодом встановите глобальну знижку для Кошика (Cart).
+
+```php
+Cart::setDiscount($rowId, 21);
+$cart->setDiscount($rowId, 21);
+```
+
+### Buyable
+
+Для зручного швидкого додавання товарів до кошика та їхнього автоматичного об'єднання, ваша модель повинна запустити інтерфейс `Buyable`. Ви можете застосовувати `CanBeBought` трейт для імплементації необхідних методів, але зверніть увагу, що такі методи застосовуватимуть попередньо визначені поля у вашій моделі для необхідних значень.
+```php
+id;
+ }
+ public function getBuyableDescription(){
+ return $this->name;
+ }
+ public function getBuyablePrice(){
+ return $this->price;
+ }
+ public function getBuyableWeight(){
+ return $this->weight;
+ }
+```
+
+Приклад:
+
+```php
+id;
+ }
+ public function getBuyableDescription($options = null) {
+ return $this->name;
+ }
+ public function getBuyablePrice($options = null) {
+ return $this->price;
+ }
+}
+```
+
+## Колекції
+
+Щодо багатьох екземплярів Кошик (Cart) повертає Колекцію, яка є простим видом Laravel Collection. Таким чином усі методи, які ви можете застосовувати щодо Laravel Collection, є також доступними у результаті операції.
+
+Наприклад, ви можете швидко отримати кількість унікальних товарів у кошику:
+
+```php
+Cart::content()->count();
+```
+
+Або групувати вміст за ідентифікатором товару:
+
+```php
+Cart::content()->groupBy('id');
+```
+
+## Екземпляри
+
+Пакет підтримує декілька екземплярів кошика. Як це працює:
+
+Ви можете встановити поточний екземпляр кошика через виклик `Cart::instance('newInstance')`. З цього моменту, активний екземляр кошика буде `newInstance`, тому коли ви додаєте, вилучаєте або отримуєте інформацію щодо вмісту кошика, ви працюєте з екземпляром `newInstance` кошика.
+Якщо ви хочете переключитися між екзмеплярами, ви можете викликати `Cart::instance('otherInstance')` ще раз, і ви знову працюватимете з `otherInstance`.
+
+Короткий приклад:
+
+```php
+Cart::instance('shopping')->add('192ao12', 'Product 1', 1, 9.99, 550);
+
+// Get the content of the 'shopping' cart
+Cart::content();
+
+Cart::instance('wishlist')->add('sdjk922', 'Product 2', 1, 19.95, 550, ['size' => 'medium']);
+
+// Get the content of the 'wishlist' cart
+Cart::content();
+
+// If you want to get the content of the 'shopping' cart again
+Cart::instance('shopping')->content();
+
+// And the count of the 'wishlist' cart again
+Cart::instance('wishlist')->count();
+```
+
+Ви також можете застосувати Контракт `InstanceIdentifier` для розширення бажаної моделі через призначення / створення екземпляру Кошика (Cart) для неї. Така дія також дозволить напряму встановлювати глобальну знижку.
+```
+email;
+ }
+
+ /**
+ * Get the unique identifier to load the Cart from
+ *
+ * @return int|string
+ */
+ public function getInstanceGlobalDiscount($options = null)
+ {
+ return $this->discountRate ?: 0;
+ }
+}
+
+// Inside Controller
+$user = \Auth::user();
+$cart = Cart::instance($user);
+
+
+
+```
+
+**N.B. Зверніть увагу, що кошик залишається у стані останнього призначеного екземпляра, доки ви не встановите інший екземпляр протягом виконання скрипта.**
+
+**N.B.2 За замовчуванням екземпляр кошика називається `default`, тому коли ви не використовуєте екземпляри, `Cart::content();` залишається таким самим як і `Cart::instance('default')->content()`.**
+
+## Моделі
+
+Через те, що можливість прямого доступу до моделі з CartItem може бути дуже зручною, виникає питання чи можливо об'єднати модель із товарами у кошику. Скажімо, у вашому застосунку є модель `Product`. Завдяки методу `associate()` ви можете вказати кошику, що товар у кошику об'єднаний з моделлю `Product`.
+
+Таким чином ви можете отримати доступ до вашої моделі одразу з `CartItem`!
+
+Доступ до моделі також можна отримати через властивість CartItem `model`.
+
+**Якщо ваша модель запускає інтерфейс `Buyable` і ви використовували вашу модель для додавання товару до кошика, вони будуть об'єднані автоматично.**
+
+Ось приклад:
+
+```php
+
+// First we'll add the item to the cart.
+$cartItem = Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large']);
+
+// Next we associate a model with the item.
+Cart::associate($cartItem->rowId, 'Product');
+
+// Or even easier, call the associate method on the CartItem!
+$cartItem->associate('Product');
+
+// You can even make it a one-liner
+Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large'])->associate('Product');
+
+// Now, when iterating over the content of the cart, you can access the model.
+foreach(Cart::content() as $row) {
+ echo 'You have ' . $row->qty . ' items of ' . $row->model->name . ' with description: "' . $row->model->description . '" in your cart.';
+}
+```
+## База даних
+
+- [Конфігурації](#configuration)
+- [Збереження кошика](#storing-the-cart)
+- [Відновлення кошика](#restoring-the-cart)
+
+### Конфігурації
+Для збереження кошика до бази даних, щоб ви могли отримати його пізніше, пакет повинен знати яке підключення до бази даних використовувати і яка назва окремої таблиці.
+За замовчуванням, пакет використовуватиме підключення до бази даних, яке вказане за замовчуванням, та використовуватиме таблицію `shoppingcart`.
+Якщо ви хочете змінити ці значення, вам потрібно буде опублікувати файл з конфігураціями `config`.
+
+ php artisan vendor:publish --provider="Gloudemans\Shoppingcart\ShoppingcartServiceProvider" --tag="config"
+
+Така дія створить вам файл з конфігураціями `cart.php`, в якому ви можете внести бажані зміни.
+
+Щоб спростити ваше життя, пакет також включає готову до вжитку `migration`, яку можна опублікувати через запуск наступної команди:
+
+ php artisan vendor:publish --provider="Gloudemans\Shoppingcart\ShoppingcartServiceProvider" --tag="migrations"
+
+Така дія розмістить файл з міграцією таблиці `shoppingcart` в директорію `database/migrations`. Все що вам залишається зробити, це запустити `php artisan migrate` для міграції вашої бази даних.
+
+### Збереження кошика
+Для збереження екземпляра кошика до бази даних, вам потрібно викликати метод `store($identifier) `. Де `$identifier` є випадковим ключем, наприклад, ідентифікатор або ім'я користувача.
+
+ Cart::store('username');
+
+ // To store a cart instance named 'wishlist'
+ Cart::instance('wishlist')->store('username');
+
+### Відновлення кошика
+Якщо ви хочете отримати кошик із бази даних і відновити його, вам знадобиться викликати метод `restore($identifier)`, де `$identifier` - це ключ, який ви зазначили у методі `store`.
+
+ Cart::restore('username');
+
+ // To restore a cart instance named 'wishlist'
+ Cart::instance('wishlist')->restore('username');
+
+### Злиття кошиків
+Якщо ви хочете злити кошик із іншим кошиком, збереженим у базі даних, вам знадобиться викликати метод `merge($identifier)`, де `$identifier` - це ключ, який ви зазначили у методі`store`. Ви також можете визначити чи хочете ви зберегти знижку і ставку оподаткування для товарів.
+
+ // Merge the contents of 'savedcart' into 'username'.
+ Cart::instance('username')->merge('savedcart', $keepDiscount, $keepTaxrate);
+
+## Перехоплення
+
+Пакет Кошик (Cart) видаватиме винятки/перехоплення у разі, якщо щось йде не за планом. Таким чином, вам буде простіше відлагоджувати (debug) ваш код, використовуючи пакет Кошик, або обробляти помилку за типом перехоплення. Пакети Кошика можуть видавати наступні перехоплення:
+
+| Перехоплення | Пояснення |
+| ---------------------------- | ---------------------------------------------------------------------------------- |
+| *CartAlreadyStoredException* | ПерехопленняКошикВжеЗбережено Коли ви намагаєтеся зберегти кошик, який вже було збережено, застосовуючи вказаний ідентифікатор |
+| *InvalidRowIDException* | ПерехопленняНеправильнийІдРядка Коли rowId, який було передано, не існує у поточному екземплярі кошика |
+| *UnknownModelException* | ПерехопленняНевідомаМодель Коли ви намагаєтеся об'єднати неіснуючу модель з CartItem. |
+
+## Події
+
+Кошик також має вбудовані події. Існує п'ять подій, які можна очікувати.
+
+| Подія | Видано | Параметр |
+| ------------- | ---------------------------------------- | -------------------------------- |
+| cart.added | Коли товар додано до кошика. | `CartItem`, який було додано. |
+| cart.updated | Коли товар оновлено у кошику. | `CartItem`, який було оновлено. |
+| cart.removed | Коли товар вилучено з кошика. | `CartItem`, який було вилучено. |
+| cart.stored | Коли вміст кошика було збережено. | - |
+| cart.restored | Коли вміст кошика було відновлено. | - |
+
+## Приклад
+
+Нижче наведено приклад як відобразити вміст кошика у таблиці:
+
+```php
+
+// Add some items in your Controller.
+Cart::add('192ao12', 'Product 1', 1, 9.99);
+Cart::add('1239ad0', 'Product 2', 2, 5.95, ['size' => 'large']);
+
+// Display the content in a View.
+
+```
diff --git a/composer.json b/composer.json
index 80d0396..3825978 100644
--- a/composer.json
+++ b/composer.json
@@ -6,18 +6,20 @@
"authors": [
{
"name": "Rob Gloudemans",
- "email": "info@robgloudemans.nl"
+ "email": "info@robgloudemans.nl",
+ "homepage": "http://robgloudemans.nl/"
},
{
"name": "Patrick Henninger",
- "email": "privat@skyraptor.eu"
+ "email": "privat@skyraptor.eu",
+ "homepage": "https://skyraptor.eu/"
}
],
"require": {
- "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*",
- "illuminate/session": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*",
- "illuminate/events": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*",
- "nesbot/carbon": "^1.26.3 || ^2.0"
+ "illuminate/support": "5.4.*||5.5.*||5.6.*||5.7.*||5.8.*||^6.0||^7.0",
+ "illuminate/session": "5.4.*||5.5.*||5.6.*||5.7.*||5.8.*||^6.0||^7.0",
+ "illuminate/events": "5.4.*||5.5.*||5.6.*||5.7.*||5.8.*||^6.0||^7.0",
+ "nesbot/carbon": "~1.20||^1.26.3||^2.0"
},
"require-dev": {
"phpunit/phpunit": "~5.0||~6.0||~7.0||~8.0",
diff --git a/src/Cart.php b/src/Cart.php
index 2856606..182ef29 100644
--- a/src/Cart.php
+++ b/src/Cart.php
@@ -61,7 +61,7 @@ class Cart
private $discount = 0;
/**
- * Defines the discount percentage.
+ * Defines the tax rate.
*
* @var float
*/
@@ -120,11 +120,12 @@ class Cart
* @param mixed $name
* @param int|float $qty
* @param float $price
+ * @param float $weight
* @param array $options
*
* @return \Gloudemans\Shoppingcart\CartItem
*/
- public function add($id, $name = null, $qty = null, $price = null, array $options = [])
+ public function add($id, $name = null, $qty = null, $price = null, $weight = 0, array $options = [])
{
if ($this->isMulti($id)) {
return array_map(function ($item) {
@@ -132,7 +133,7 @@ class Cart
}, $id);
}
- $cartItem = $this->createCartItem($id, $name, $qty, $price, $options);
+ $cartItem = $this->createCartItem($id, $name, $qty, $price, $weight, $options);
return $this->addCartItem($cartItem);
}
@@ -140,13 +141,14 @@ class Cart
/**
* Add an item to the cart.
*
- * @param \Gloudemans\Shoppingcart\CartItem $item Item to add to the Cart
- * @param bool $keepDiscount Keep the discount rate of the Item
- * @param bool $keepTax Keep the Tax rate of the Item
+ * @param \Gloudemans\Shoppingcart\CartItem $item Item to add to the Cart
+ * @param bool $keepDiscount Keep the discount rate of the Item
+ * @param bool $keepTax Keep the Tax rate of the Item
+ * @param bool $dispatchEvent
*
* @return \Gloudemans\Shoppingcart\CartItem The CartItem
*/
- public function addCartItem($item, $keepDiscount = false, $keepTax = false)
+ public function addCartItem($item, $keepDiscount = false, $keepTax = false, $dispatchEvent = true)
{
if (!$keepDiscount) {
$item->setDiscountRate($this->discount);
@@ -164,7 +166,9 @@ class Cart
$content->put($item->rowId, $item);
- $this->events->dispatch('cart.added', $item);
+ if ($dispatchEvent) {
+ $this->events->dispatch('cart.added', $item);
+ }
$this->session->put($this->instance, $content);
@@ -194,6 +198,8 @@ class Cart
$content = $this->getContent();
if ($rowId !== $cartItem->rowId) {
+ $itemOldIndex = $content->keys()->search($rowId);
+
$content->pull($rowId);
if ($content->has($cartItem->rowId)) {
@@ -207,7 +213,13 @@ class Cart
return;
} else {
- $content->put($cartItem->rowId, $cartItem);
+ if (isset($itemOldIndex)) {
+ $content = $content->slice(0, $itemOldIndex)
+ ->merge([$cartItem->rowId => $cartItem])
+ ->merge($content->slice($itemOldIndex));
+ } else {
+ $content->put($cartItem->rowId, $cartItem);
+ }
}
$this->events->dispatch('cart.updated', $cartItem);
@@ -378,7 +390,7 @@ class Cart
}
/**
- * Get the subtotal (total - tax) of the items in the cart.
+ * Get the discount of the items in the cart.
*
* @return float
*/
@@ -390,7 +402,7 @@ class Cart
}
/**
- * Get the subtotal (total - tax) of the items in the cart as formatted string.
+ * Get the discount of the items in the cart as formatted string.
*
* @param int $decimals
* @param string $decimalPoint
@@ -404,7 +416,7 @@ class Cart
}
/**
- * Get the subtotal (total - tax) of the items in the cart.
+ * Get the price of the items in the cart (not rounded).
*
* @return float
*/
@@ -416,7 +428,7 @@ class Cart
}
/**
- * Get the subtotal (total - tax) of the items in the cart as formatted string.
+ * Get the price of the items in the cart as formatted string.
*
* @param int $decimals
* @param string $decimalPoint
@@ -429,6 +441,32 @@ class Cart
return $this->numberFormat($this->initialFloat(), $decimals, $decimalPoint, $thousandSeperator);
}
+ /**
+ * Get the price of the items in the cart (previously rounded).
+ *
+ * @return float
+ */
+ public function priceTotalFloat()
+ {
+ return $this->getContent()->reduce(function ($initial, CartItem $cartItem) {
+ return $initial + $cartItem->priceTotal;
+ }, 0);
+ }
+
+ /**
+ * Get the price of the items in the cart as formatted string.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ *
+ * @return string
+ */
+ public function priceTotal($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ return $this->numberFormat($this->priceTotalFloat(), $decimals, $decimalPoint, $thousandSeperator);
+ }
+
/**
* Get the total weight of the items in the cart.
*
@@ -643,8 +681,29 @@ class Cart
$this->createdAt = Carbon::parse(data_get($stored, 'created_at'));
$this->updatedAt = Carbon::parse(data_get($stored, 'updated_at'));
- $this->getConnection()->table($this->getTableName())
- ->where('identifier', $identifier)->delete();
+ $this->getConnection()->table($this->getTableName())->where('identifier', $identifier)->delete();
+ }
+
+ /**
+ * Erase the cart with the given identifier.
+ *
+ * @param mixed $identifier
+ *
+ * @return void
+ */
+ public function erase($identifier)
+ {
+ if ($identifier instanceof InstanceIdentifier) {
+ $identifier = $identifier->getInstanceIdentifier();
+ }
+
+ if (!$this->storedCartWithIdentifierExists($identifier)) {
+ return;
+ }
+
+ $this->getConnection()->table($this->getTableName())->where('identifier', $identifier)->delete();
+
+ $this->events->dispatch('cart.erased');
}
/**
@@ -653,10 +712,11 @@ class Cart
* @param mixed $identifier Identifier of the Cart to merge with.
* @param bool $keepDiscount Keep the discount of the CartItems.
* @param bool $keepTax Keep the tax of the CartItems.
+ * @param bool $dispatchAdd Flag to dispatch the add events.
*
* @return bool
*/
- public function merge($identifier, $keepDiscount = false, $keepTax = false)
+ public function merge($identifier, $keepDiscount = false, $keepTax = false, $dispatchAdd = true)
{
if (!$this->storedCartWithIdentifierExists($identifier)) {
return false;
@@ -668,9 +728,11 @@ class Cart
$storedContent = unserialize($stored->content);
foreach ($storedContent as $cartItem) {
- $this->addCartItem($cartItem, $keepDiscount, $keepTax);
+ $this->addCartItem($cartItem, $keepDiscount, $keepTax, $dispatchAdd);
}
+ $this->events->dispatch('cart.merged');
+
return true;
}
@@ -716,11 +778,12 @@ class Cart
* @param mixed $name
* @param int|float $qty
* @param float $price
+ * @param float $weight
* @param array $options
*
* @return \Gloudemans\Shoppingcart\CartItem
*/
- private function createCartItem($id, $name, $qty, $price, array $options)
+ private function createCartItem($id, $name, $qty, $price, $weight, array $options)
{
if ($id instanceof Buyable) {
$cartItem = CartItem::fromBuyable($id, $qty ?: []);
@@ -730,7 +793,7 @@ class Cart
$cartItem = CartItem::fromArray($id);
$cartItem->setQuantity($id['qty']);
} else {
- $cartItem = CartItem::fromAttributes($id, $name, $price, $options);
+ $cartItem = CartItem::fromAttributes($id, $name, $price, $weight, $options);
$cartItem->setQuantity($qty);
}
diff --git a/src/CartItem.php b/src/CartItem.php
index 0717ed7..63589b5 100644
--- a/src/CartItem.php
+++ b/src/CartItem.php
@@ -5,7 +5,20 @@ namespace Gloudemans\Shoppingcart;
use Gloudemans\Shoppingcart\Contracts\Buyable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
+use Illuminate\Support\Arr;
+/**
+ * @property-read mixed discount
+ * @property-read float discountTotal
+ * @property-read float priceTarget
+ * @property-read float priceNet
+ * @property-read float priceTotal
+ * @property-read float subtotal
+ * @property-read float taxTotal
+ * @property-read float tax
+ * @property-read float total
+ * @property-read float priceTax
+ */
class CartItem implements Arrayable, Jsonable
{
/**
@@ -57,6 +70,13 @@ class CartItem implements Arrayable, Jsonable
*/
public $options;
+ /**
+ * The tax rate for the cart item.
+ *
+ * @var int|float
+ */
+ public $taxRate = 0;
+
/**
* The FQN of the associated model.
*
@@ -64,13 +84,6 @@ class CartItem implements Arrayable, Jsonable
*/
private $associatedModel = null;
- /**
- * The tax rate for the cart item.
- *
- * @var int|float
- */
- private $taxRate = 0;
-
/**
* The discount rate for the cart item.
*
@@ -84,6 +97,7 @@ class CartItem implements Arrayable, Jsonable
* @param int|string $id
* @param string $name
* @param float $price
+ * @param float $weight
* @param array $options
*/
public function __construct($id, $name, $price, $weight = 0, array $options = [])
@@ -97,6 +111,9 @@ class CartItem implements Arrayable, Jsonable
if (strlen($price) < 0 || !is_numeric($price)) {
throw new \InvalidArgumentException('Please supply a valid price.');
}
+ if (strlen($weight) < 0 || !is_numeric($weight)) {
+ throw new \InvalidArgumentException('Please supply a valid weight.');
+ }
$this->id = $id;
$this->name = $name;
@@ -248,6 +265,20 @@ class CartItem implements Arrayable, Jsonable
return $this->numberFormat($this->discountTotal, $decimals, $decimalPoint, $thousandSeperator);
}
+ /**
+ * Returns the formatted total price for this cart item.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ *
+ * @return string
+ */
+ public function priceTotal($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ return $this->numberFormat($this->priceTotal, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
/**
* Set the quantity for this cart item.
*
@@ -274,7 +305,6 @@ class CartItem implements Arrayable, Jsonable
$this->id = $item->getBuyableIdentifier($this->options);
$this->name = $item->getBuyableDescription($this->options);
$this->price = $item->getBuyablePrice($this->options);
- $this->priceTax = $this->price + $this->tax;
}
/**
@@ -286,13 +316,12 @@ class CartItem implements Arrayable, Jsonable
*/
public function updateFromArray(array $attributes)
{
- $this->id = array_get($attributes, 'id', $this->id);
- $this->qty = array_get($attributes, 'qty', $this->qty);
- $this->name = array_get($attributes, 'name', $this->name);
- $this->price = array_get($attributes, 'price', $this->price);
- $this->weight = array_get($attributes, 'weight', $this->weight);
- $this->priceTax = $this->price + $this->tax;
- $this->options = new CartItemOptions(array_get($attributes, 'options', $this->options));
+ $this->id = Arr::get($attributes, 'id', $this->id);
+ $this->qty = Arr::get($attributes, 'qty', $this->qty);
+ $this->name = Arr::get($attributes, 'name', $this->name);
+ $this->price = Arr::get($attributes, 'price', $this->price);
+ $this->weight = Arr::get($attributes, 'weight', $this->weight);
+ $this->options = new CartItemOptions(Arr::get($attributes, 'options', $this->options));
$this->rowId = $this->generateRowId($this->id, $this->options->all());
}
@@ -351,39 +380,69 @@ class CartItem implements Arrayable, Jsonable
if (property_exists($this, $attribute)) {
return $this->{$attribute};
}
+ $decimals = config('cart.format.decimals', 2);
switch ($attribute) {
- case 'discount':
- return $this->price * ($this->discountRate / 100);
- case 'priceTarget':
- return $this->price - $this->discount;
- case 'subtotal':
- return $this->priceTarget * $this->qty;
- case 'tax':
- return $this->priceTarget * ($this->taxRate / 100);
- case 'priceTax':
- return $this->priceTarget + $this->tax;
- case 'total':
- return $this->priceTax * $this->qty;
- case 'taxTotal':
- return $this->tax * $this->qty;
- case 'discountTotal':
- return $this->discount * $this->qty;
- case 'weightTotal':
- return $this->weight * $this->qty;
-
case 'model':
if (isset($this->associatedModel)) {
return with(new $this->associatedModel())->find($this->id);
}
-
case 'modelFQCN':
if (isset($this->associatedModel)) {
return $this->associatedModel;
}
+ case 'weightTotal':
+ return round($this->weight * $this->qty, $decimals);
+ }
- default:
- return;
+ if (config('cart.gross_price')) {
+ switch ($attribute) {
+ case 'priceNet':
+ return round($this->price / (1 + ($this->taxRate / 100)), $decimals);
+ case 'discount':
+ return $this->priceNet * ($this->discountRate / 100);
+ case 'tax':
+ return round($this->priceTarget * ($this->taxRate / 100), $decimals);
+ case 'priceTax':
+ return round($this->priceTarget + $this->tax, $decimals);
+ case 'discountTotal':
+ return round($this->discount * $this->qty, $decimals);
+ case 'priceTotal':
+ return round($this->priceNet * $this->qty, $decimals);
+ case 'subtotal':
+ return round($this->priceTotal - $this->discountTotal, $decimals);
+ case 'priceTarget':
+ return round(($this->priceTotal - $this->discountTotal) / $this->qty, $decimals);
+ case 'taxTotal':
+ return round($this->subtotal * ($this->taxRate / 100), $decimals);
+ case 'total':
+ return round($this->subtotal + $this->taxTotal, $decimals);
+ default:
+ return;
+ }
+ } else {
+ switch ($attribute) {
+ case 'discount':
+ return $this->price * ($this->discountRate / 100);
+ case 'tax':
+ return round($this->priceTarget * ($this->taxRate / 100), $decimals);
+ case 'priceTax':
+ return round($this->priceTarget + $this->tax, $decimals);
+ case 'discountTotal':
+ return round($this->discount * $this->qty, $decimals);
+ case 'priceTotal':
+ return round($this->price * $this->qty, $decimals);
+ case 'subtotal':
+ return round($this->priceTotal - $this->discountTotal, $decimals);
+ case 'priceTarget':
+ return round(($this->priceTotal - $this->discountTotal) / $this->qty, $decimals);
+ case 'taxTotal':
+ return round($this->subtotal * ($this->taxRate / 100), $decimals);
+ case 'total':
+ return round($this->subtotal + $this->taxTotal, $decimals);
+ default:
+ return;
+ }
}
}
@@ -409,7 +468,7 @@ class CartItem implements Arrayable, Jsonable
*/
public static function fromArray(array $attributes)
{
- $options = array_get($attributes, 'options', []);
+ $options = Arr::get($attributes, 'options', []);
return new self($attributes['id'], $attributes['name'], $attributes['price'], $attributes['weight'], $options);
}
diff --git a/src/Config/cart.php b/src/Config/cart.php
index a437d69..739265e 100644
--- a/src/Config/cart.php
+++ b/src/Config/cart.php
@@ -2,6 +2,18 @@
return [
+ /*
+ |--------------------------------------------------------------------------
+ | Gross price as base price
+ |--------------------------------------------------------------------------
+ |
+ | This default value is used to select the method to calculate prices and taxes
+ | If true the item price is managed as a gross price, so taxes will be calculated by separation/exclusion
+ |
+ */
+
+ 'gross_price' => false,
+
/*
|--------------------------------------------------------------------------
| Default tax rate
diff --git a/src/ShoppingcartServiceProvider.php b/src/ShoppingcartServiceProvider.php
index a26ef89..2e6b1b5 100644
--- a/src/ShoppingcartServiceProvider.php
+++ b/src/ShoppingcartServiceProvider.php
@@ -30,6 +30,6 @@ class ShoppingcartServiceProvider extends ServiceProvider
$this->publishes([
realpath(__DIR__.'/Database/migrations') => $this->app->databasePath().'/migrations',
- ]);
+ ], 'migrations');
}
}
diff --git a/tests/CartTest.php b/tests/CartTest.php
index b51863d..24da3cf 100644
--- a/tests/CartTest.php
+++ b/tests/CartTest.php
@@ -264,6 +264,19 @@ class CartTest extends TestCase
$cart->add(1, 'Some title', 1, 'invalid');
}
+ /**
+ * @test
+ */
+ public function it_will_validate_the_weight()
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Please supply a valid weight');
+
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Some title', 1, 10.00, 'invalid');
+ }
+
/** @test */
public function it_will_update_the_cart_if_the_item_already_exists_in_the_cart()
{
@@ -386,6 +399,21 @@ class CartTest extends TestCase
$this->assertRowsInCart(1, $cart);
}
+ /** @test */
+ public function it_will_keep_items_sequence_if_the_options_changed()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(), 1, ['color' => 'red']);
+ $cart->add(new BuyableProduct(), 1, ['color' => 'green']);
+ $cart->add(new BuyableProduct(), 1, ['color' => 'blue']);
+
+ $cart->update($cart->content()->values()[1]->rowId, ['options' => ['color' => 'yellow']]);
+
+ $this->assertRowsInCart(3, $cart);
+ $this->assertEquals('yellow', $cart->content()->values()[1]->options->color);
+ }
+
/** @test */
public function it_can_remove_an_item_from_the_cart()
{
@@ -743,6 +771,20 @@ class CartTest extends TestCase
$this->assertEquals('1.050,00', $cart->tax(2, ',', '.'));
}
+ /** @test */
+ public function it_can_access_tax_as_percentage()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+
+ $cart->setTax('027c91341fd5cf4d2579b49c4b6a90da', 19);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(19, $cartItem->taxRate);
+ }
+
/** @test */
public function it_can_return_the_subtotal()
{
@@ -917,6 +959,52 @@ class CartTest extends TestCase
$this->assertEquals(11.90, $cartItem->total(2));
}
+ /** @test */
+ public function it_can_calculate_all_values_after_updating_from_array()
+ {
+ $cart = $this->getCartDiscount(50);
+ $cart->add(new BuyableProduct(1, 'First item', 10.00), 1);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', ['qty'=>2]);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $cart->setTax('027c91341fd5cf4d2579b49c4b6a90da', 19);
+
+ $this->assertEquals(10.00, $cartItem->price(2));
+ $this->assertEquals(5.00, $cartItem->discount(2));
+ $this->assertEquals(10.00, $cartItem->discountTotal(2));
+ $this->assertEquals(5.00, $cartItem->priceTarget(2));
+ $this->assertEquals(10.00, $cartItem->subtotal(2));
+ $this->assertEquals(0.95, $cartItem->tax(2));
+ $this->assertEquals(1.90, $cartItem->taxTotal(2));
+ $this->assertEquals(5.95, $cartItem->priceTax(2));
+ $this->assertEquals(11.90, $cartItem->total(2));
+ }
+
+ /** @test */
+ public function it_can_calculate_all_values_after_updating_from_buyable()
+ {
+ $cart = $this->getCartDiscount(50);
+ $cart->add(new BuyableProduct(1, 'First item', 5.00), 2);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', new BuyableProduct(1, 'First item', 10.00));
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $cart->setTax('027c91341fd5cf4d2579b49c4b6a90da', 19);
+
+ $this->assertEquals(10.00, $cartItem->price(2));
+ $this->assertEquals(5.00, $cartItem->discount(2));
+ $this->assertEquals(10.00, $cartItem->discountTotal(2));
+ $this->assertEquals(5.00, $cartItem->priceTarget(2));
+ $this->assertEquals(10.00, $cartItem->subtotal(2));
+ $this->assertEquals(0.95, $cartItem->tax(2));
+ $this->assertEquals(1.90, $cartItem->taxTotal(2));
+ $this->assertEquals(5.95, $cartItem->priceTax(2));
+ $this->assertEquals(11.90, $cartItem->total(2));
+ }
+
/** @test */
public function it_will_destroy_the_cart_when_the_user_logs_out_and_the_config_setting_was_set_to_true()
{
@@ -961,7 +1049,7 @@ class CartTest extends TestCase
}
/** @test */
- public function cart_hast_no_rounding_errors()
+ public function cart_has_no_rounding_errors()
{
$cart = $this->getCart();
@@ -1149,6 +1237,135 @@ class CartTest extends TestCase
$this->assertEquals(2.50, $cart->tax(2)); // tax of 5 Bucks
}
+ /** @test */
+ public function it_does_allow_adding_cart_items_with_weight_and_options()
+ {
+ // https://github.com/bumbummen99/LaravelShoppingcart/pull/5
+ $cart = $this->getCart();
+
+ $cartItem = $cart->add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large']);
+
+ $this->assertEquals(550, $cartItem->weight);
+ $this->assertTrue($cartItem->options->has('size'));
+ $this->assertEquals('large', $cartItem->options->size);
+ }
+
+ /** @test */
+ public function it_can_merge_without_dispatching_add_events()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ $cart = $this->getCartDiscount(50);
+ $cart->add(new BuyableProduct(1, 'Item', 10.00), 1);
+ $cart->add(new BuyableProduct(2, 'Item 2', 10.00), 1);
+ $cart->store('test');
+
+ Event::fakeFor(function () {
+ $cart2 = $this->getCart();
+ $cart2->instance('test2');
+ $cart2->setGlobalTax(0);
+ $cart2->setGlobalDiscount(0);
+
+ $this->assertEquals('0', $cart2->countInstances());
+
+ $cart2->merge('test', null, null, false);
+
+ Event::assertNotDispatched('cart.added');
+ Event::assertDispatched('cart.merged');
+
+ $this->assertEquals('2', $cart2->countInstances());
+ $this->assertEquals(20, $cart2->totalFloat());
+ });
+ }
+
+ /** @test */
+ public function it_can_merge_dispatching_add_events()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ $cart = $this->getCartDiscount(50);
+ $cart->add(new BuyableProduct(1, 'Item', 10.00), 1);
+ $cart->add(new BuyableProduct(2, 'Item 2', 10.00), 1);
+ $cart->store('test');
+
+ Event::fakeFor(function () {
+ $cart2 = $this->getCart();
+ $cart2->instance('test2');
+ $cart2->setGlobalTax(0);
+ $cart2->setGlobalDiscount(0);
+
+ $this->assertEquals('0', $cart2->countInstances());
+
+ $cart2->merge('test');
+
+ Event::assertDispatched('cart.added', 2);
+ Event::assertDispatched('cart.merged');
+ $this->assertEquals('2', $cart2->countInstances());
+ $this->assertEquals(20, $cart2->totalFloat());
+ });
+ }
+
+ /** @test */
+ public function it_use_correctly_rounded_values_for_totals_and_cart_summary()
+ {
+ $this->setConfigFormat(2, ',', '');
+
+ $cart = $this->getCartDiscount(6);
+
+ $cartItem = $cart->add(new BuyableProduct(1, 'First item', 0.18929), 1000);
+ $cart->add(new BuyableProduct(2, 'Second item', 4.41632), 5);
+ $cart->add(new BuyableProduct(3, 'Third item', 0.37995), 25);
+
+ $cart->setGlobalTax(22);
+
+ // check total
+ $this->assertEquals('253,29', $cart->total());
+
+ // check that the sum of cart subvalues matches the total (in order to avoid cart summary to looks wrong)
+ $this->assertEquals($cart->totalFloat(), $cart->subtotalFloat() + $cart->taxFloat());
+ }
+
+ /** @test */
+ public function it_use_gross_price_as_base_price()
+ {
+ $cart = $this->getCartDiscount(0);
+ config(['cart.gross_price' => true]);
+
+ $cartItem = $cart->add(new BuyableProduct(1, 'First item', 100), 2);
+
+ $cart->setGlobalTax(22);
+
+ // check net price
+ $this->assertEquals(81.97, round($cartItem->priceNet, 2));
+ }
+
+ /** @test */
+ public function it_use_gross_price_and_it_use_correctly_rounded_values_for_totals_and_cart_summary()
+ {
+ $this->setConfigFormat(2, ',', '');
+ config(['cart.gross_price' => true]);
+
+ $cart = $this->getCartDiscount(6);
+
+ $cartItem = $cart->add(new BuyableProduct(1, 'First item', 0.23093), 1000);
+ $cart->add(new BuyableProduct(2, 'Second item', 5.38791), 5);
+ $cart->add(new BuyableProduct(3, 'Third item', 0.46354), 25);
+
+ $cart->setGlobalTax(22);
+
+ // check total
+ $this->assertEquals('254,12', $cart->total());
+
+ // check item price total
+ $this->assertEquals(190, $cartItem->priceTotal);
+ // check that the sum of cart subvalues matches the total (in order to avoid cart summary to looks wrong)
+ $this->assertEquals($cart->totalFloat(), $cart->subtotalFloat() + $cart->taxFloat());
+ }
+
/**
* Get an instance of the cart.
*
@@ -1165,12 +1382,14 @@ class CartTest extends TestCase
/**
* Get an instance of the cart with discount.
*
+ * @param int $discount
+ *
* @return \Gloudemans\Shoppingcart\Cart
*/
- private function getCartDiscount($discount = 0)
+ private function getCartDiscount($discount = 50)
{
$cart = $this->getCart();
- $cart->setGlobalDiscount(50);
+ $cart->setGlobalDiscount($discount);
return $cart;
}