diff --git a/packages/Webkul/Admin/src/DataGrids/AddressDataGrid.php b/packages/Webkul/Admin/src/DataGrids/AddressDataGrid.php index 59997b828..ede09c495 100644 --- a/packages/Webkul/Admin/src/DataGrids/AddressDataGrid.php +++ b/packages/Webkul/Admin/src/DataGrids/AddressDataGrid.php @@ -3,6 +3,7 @@ namespace Webkul\Admin\DataGrids; use Illuminate\Support\Facades\DB; +use Webkul\Customer\Models\CustomerAddress; use Webkul\Ui\DataGrid\DataGrid; use Webkul\Customer\Repositories\CustomerRepository; @@ -43,10 +44,11 @@ class AddressDataGrid extends DataGrid { $customer = $this->customerRepository->find(request('id')); - $queryBuilder = DB::table('customer_addresses as ca') + $queryBuilder = DB::table('addresses as ca') ->leftJoin('countries', 'ca.country', '=', 'countries.code') ->leftJoin('customers as c', 'ca.customer_id', '=', 'c.id') ->addSelect('ca.id as address_id', 'ca.company_name', 'ca.address1', 'ca.country', DB::raw('' . DB::getTablePrefix() . 'countries.name as country_name'), 'ca.state', 'ca.city', 'ca.postcode', 'ca.phone', 'ca.default_address') + ->where('ca.address_type', CustomerAddress::ADDRESS_TYPE) ->where('c.id', $customer->id); $queryBuilder = $queryBuilder->leftJoin('country_states', function($qb) { diff --git a/packages/Webkul/Admin/src/DataGrids/OrderDataGrid.php b/packages/Webkul/Admin/src/DataGrids/OrderDataGrid.php index 718cb4071..50673e5fa 100755 --- a/packages/Webkul/Admin/src/DataGrids/OrderDataGrid.php +++ b/packages/Webkul/Admin/src/DataGrids/OrderDataGrid.php @@ -3,6 +3,7 @@ namespace Webkul\Admin\DataGrids; use Illuminate\Support\Facades\DB; +use Webkul\Sales\Models\OrderAddress; use Webkul\Ui\DataGrid\DataGrid; class OrderDataGrid extends DataGrid @@ -14,13 +15,13 @@ class OrderDataGrid extends DataGrid public function prepareQueryBuilder() { $queryBuilder = DB::table('orders') - ->leftJoin('order_address as order_address_shipping', function($leftJoin) { + ->leftJoin('addresses as order_address_shipping', function($leftJoin) { $leftJoin->on('order_address_shipping.order_id', '=', 'orders.id') - ->where('order_address_shipping.address_type', 'shipping'); + ->where('order_address_shipping.address_type', OrderAddress::ADDRESS_TYPE_SHIPPING); }) - ->leftJoin('order_address as order_address_billing', function($leftJoin) { + ->leftJoin('addresses as order_address_billing', function($leftJoin) { $leftJoin->on('order_address_billing.order_id', '=', 'orders.id') - ->where('order_address_billing.address_type', 'billing'); + ->where('order_address_billing.address_type', OrderAddress::ADDRESS_TYPE_BILLING); }) ->addSelect('orders.id','orders.increment_id', 'orders.base_sub_total', 'orders.base_grand_total', 'orders.created_at', 'channel_name', 'status') ->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name) as billed_to')) diff --git a/packages/Webkul/Admin/src/DataGrids/OrderRefundDataGrid.php b/packages/Webkul/Admin/src/DataGrids/OrderRefundDataGrid.php index 320182382..53fe381e8 100755 --- a/packages/Webkul/Admin/src/DataGrids/OrderRefundDataGrid.php +++ b/packages/Webkul/Admin/src/DataGrids/OrderRefundDataGrid.php @@ -3,6 +3,7 @@ namespace Webkul\Admin\DataGrids; use Illuminate\Support\Facades\DB; +use Webkul\Sales\Models\OrderAddress; use Webkul\Ui\DataGrid\DataGrid; class OrderRefundDataGrid extends DataGrid @@ -16,9 +17,9 @@ class OrderRefundDataGrid extends DataGrid $queryBuilder = DB::table('refunds') ->select('refunds.id', 'orders.increment_id', 'refunds.state', 'refunds.base_grand_total', 'refunds.created_at') ->leftJoin('orders', 'refunds.order_id', '=', 'orders.id') - ->leftJoin('order_address as order_address_billing', function($leftJoin) { + ->leftJoin('addresses as order_address_billing', function($leftJoin) { $leftJoin->on('order_address_billing.order_id', '=', 'orders.id') - ->where('order_address_billing.address_type', 'billing'); + ->where('order_address_billing.address_type', OrderAddress::ADDRESS_TYPE_BILLING); }) ->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name) as billed_to')); diff --git a/packages/Webkul/Admin/src/DataGrids/OrderShipmentsDataGrid.php b/packages/Webkul/Admin/src/DataGrids/OrderShipmentsDataGrid.php index d126c7f2a..33df62eb9 100755 --- a/packages/Webkul/Admin/src/DataGrids/OrderShipmentsDataGrid.php +++ b/packages/Webkul/Admin/src/DataGrids/OrderShipmentsDataGrid.php @@ -3,6 +3,7 @@ namespace Webkul\Admin\DataGrids; use Illuminate\Support\Facades\DB; +use Webkul\Sales\Models\OrderAddress; use Webkul\Ui\DataGrid\DataGrid; class OrderShipmentsDataGrid extends DataGrid @@ -14,9 +15,9 @@ class OrderShipmentsDataGrid extends DataGrid public function prepareQueryBuilder() { $queryBuilder = DB::table('shipments') - ->leftJoin('order_address as order_address_shipping', function($leftJoin) { + ->leftJoin('addresses as order_address_shipping', function($leftJoin) { $leftJoin->on('order_address_shipping.order_id', '=', 'shipments.order_id') - ->where('order_address_shipping.address_type', 'shipping'); + ->where('order_address_shipping.address_type', OrderAddress::ADDRESS_TYPE_SHIPPING); }) ->leftJoin('orders as ors', 'shipments.order_id', '=', 'ors.id') ->leftJoin('inventory_sources as is', 'shipments.inventory_source_id', '=', 'is.id') diff --git a/packages/Webkul/Checkout/src/Cart.php b/packages/Webkul/Checkout/src/Cart.php index 6032735d7..4a4ddd407 100755 --- a/packages/Webkul/Checkout/src/Cart.php +++ b/packages/Webkul/Checkout/src/Cart.php @@ -658,7 +658,7 @@ class Cart if (! $cart = $this->getCart()) { return; } - + Event::dispatch('checkout.cart.calculate.items.tax.before', $cart); foreach ($cart->items()->get() as $item) { @@ -1199,21 +1199,21 @@ class Cart } else { if (isset($billingAddressData['use_for_shipping']) && $billingAddressData['use_for_shipping']) { $this->cartAddressRepository->create(array_merge($billingAddressData, - ['address_type' => 'shipping'])); + ['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING])); } else { $this->cartAddressRepository->create(array_merge($shippingAddressData, - ['address_type' => 'shipping'])); + ['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING])); } } } } else { - $this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => 'billing'])); + $this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_BILLING])); if ($cart->haveStockableItems()) { if (isset($billingAddressData['use_for_shipping']) && $billingAddressData['use_for_shipping']) { - $this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => 'shipping'])); + $this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING])); } else { - $this->cartAddressRepository->create(array_merge($shippingAddressData, ['address_type' => 'shipping'])); + $this->cartAddressRepository->create(array_merge($shippingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING])); } } } diff --git a/packages/Webkul/Checkout/src/Database/Factories/CartAddressFactory.php b/packages/Webkul/Checkout/src/Database/Factories/CartAddressFactory.php index 53e389de0..c78b813e7 100644 --- a/packages/Webkul/Checkout/src/Database/Factories/CartAddressFactory.php +++ b/packages/Webkul/Checkout/src/Database/Factories/CartAddressFactory.php @@ -6,14 +6,10 @@ use Faker\Generator as Faker; use Webkul\Checkout\Models\CartAddress; $factory->define(CartAddress::class, function (Faker $faker) { - $now = date("Y-m-d H:i:s"); - return [ 'first_name' => $faker->firstName(), 'last_name' => $faker->lastName, 'email' => $faker->email, - 'created_at' => $now, - 'updated_at' => $now, - 'address_type' => 'billing', + 'address_type' => CartAddress::ADDRESS_TYPE_BILLING, ]; }); diff --git a/packages/Webkul/Checkout/src/Models/Cart.php b/packages/Webkul/Checkout/src/Models/Cart.php index 05ff14562..dbc924c63 100755 --- a/packages/Webkul/Checkout/src/Models/Cart.php +++ b/packages/Webkul/Checkout/src/Models/Cart.php @@ -48,7 +48,7 @@ class Cart extends Model implements CartContract */ public function billing_address() { - return $this->addresses()->where('address_type', 'billing'); + return $this->addresses()->where('address_type', CartAddress::ADDRESS_TYPE_BILLING); } /** @@ -64,7 +64,7 @@ class Cart extends Model implements CartContract */ public function shipping_address() { - return $this->addresses()->where('address_type', 'shipping'); + return $this->addresses()->where('address_type', CartAddress::ADDRESS_TYPE_SHIPPING); } /** diff --git a/packages/Webkul/Checkout/src/Models/CartAddress.php b/packages/Webkul/Checkout/src/Models/CartAddress.php index 307526c9a..88cb4ec29 100755 --- a/packages/Webkul/Checkout/src/Models/CartAddress.php +++ b/packages/Webkul/Checkout/src/Models/CartAddress.php @@ -2,30 +2,47 @@ namespace Webkul\Checkout\Models; -use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Builder; use Webkul\Checkout\Contracts\CartAddress as CartAddressContract; +use Webkul\Core\Models\Address; -class CartAddress extends Model implements CartAddressContract +/** + * Class CartAddress + * @package Webkul\Checkout\Models + * + * @property integer $cart_id + * @property Cart $cart + * + */ +class CartAddress extends Address implements CartAddressContract { - protected $table = 'cart_address'; + public const ADDRESS_TYPE_SHIPPING = 'cart_shipping'; + public const ADDRESS_TYPE_BILLING = 'cart_billing'; - protected $fillable = [ - 'first_name', - 'last_name', - 'email', - 'company_name', - 'vat_id', - 'address1', - 'city', - 'state', - 'postcode', - 'country', - 'phone', - 'address_type', - 'cart_id', - 'customer_id', + /** + * @var array default values + */ + protected $attributes = [ + 'address_type' => self::ADDRESS_TYPE_BILLING, ]; + /** + * The "booted" method of the model. + * + * @return void + */ + protected static function boot() + { + static::addGlobalScope('address_type', static function (Builder $builder) { + $builder->whereIn('address_type', [ + self::ADDRESS_TYPE_BILLING, + self::ADDRESS_TYPE_SHIPPING + ]); + }); + + parent::boot(); + } + /** * Get the shipping rates for the cart address. */ @@ -35,10 +52,10 @@ class CartAddress extends Model implements CartAddressContract } /** - * Get all of the attributes for the attribute groups. + * Get the cart record associated with the address. */ - public function getNameAttribute() + public function cart() { - return $this->first_name . ' ' . $this->last_name; + return $this->belongsTo(Cart::class); } } \ No newline at end of file diff --git a/packages/Webkul/Checkout/src/Models/CartShippingRate.php b/packages/Webkul/Checkout/src/Models/CartShippingRate.php index e3c8d41a3..a4b4bbe17 100755 --- a/packages/Webkul/Checkout/src/Models/CartShippingRate.php +++ b/packages/Webkul/Checkout/src/Models/CartShippingRate.php @@ -24,6 +24,7 @@ class CartShippingRate extends Model implements CartShippingRateContract */ public function shipping_address() { - return $this->belongsTo(CartAddressProxy::modelClass()); + return $this->belongsTo(CartAddressProxy::modelClass(), 'cart_address_id') + ->where('address_type', CartAddress::ADDRESS_TYPE_SHIPPING); } } \ No newline at end of file diff --git a/packages/Webkul/Core/src/Database/Migrations/2020_04_16_185147_add_table_addresses.php b/packages/Webkul/Core/src/Database/Migrations/2020_04_16_185147_add_table_addresses.php new file mode 100644 index 000000000..9288127c2 --- /dev/null +++ b/packages/Webkul/Core/src/Database/Migrations/2020_04_16_185147_add_table_addresses.php @@ -0,0 +1,294 @@ +increments('id'); + $table->string('address_type'); + $table->unsignedInteger('customer_id')->nullable()->comment('null if guest checkout'); + $table->unsignedInteger('cart_id')->nullable()->comment('only for cart_addresses'); + $table->unsignedInteger('order_id')->nullable()->comment('only for order_addresses'); + + $table->string('first_name'); + $table->string('last_name'); + $table->string('gender')->nullable(); + $table->string('company_name')->nullable(); + $table->string('address1'); + $table->string('address2')->nullable(); + $table->string('postcode'); + $table->string('city'); + $table->string('state'); + $table->string('country'); + $table->string('email')->nullable(); + $table->string('phone')->nullable(); + + $table->string('vat_id')->nullable(); + $table->boolean('default_address') + ->default(false) + ->comment('only for customer_addresses'); + + $table->json('additional')->nullable(); + + $table->timestamps(); + + $table->foreign(['customer_id'])->references('id')->on('customers')->onDelete('cascade'); + $table->foreign(['cart_id'])->references('id')->on('cart')->onDelete('cascade'); + $table->foreign(['order_id'])->references('id')->on('orders')->onDelete('cascade'); + }); + + Schema::disableForeignKeyConstraints(); + + $this->migrateCustomerAddresses(); + $this->migrateCartAddresses(); + $this->migrateOrderAddresses(); + + $this->migrateForeignKeys(); + + Schema::drop('customer_addresses'); + Schema::drop('cart_address'); + Schema::drop('order_address'); + + Schema::enableForeignKeyConstraints(); + + DB::commit(); + } catch (Exception $e) { + DB::rollBack(); + throw $e; + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + throw new Exception('you cannot revert this migration: data would be lost'); + } + + private function migrateCustomerAddresses(): void + { + $dbPrefix = DB::getTablePrefix(); + + $insertCustomerAddresses = <<< SQL + INSERT INTO ${dbPrefix}addresses( + address_type, + customer_id, + first_name, + last_name, + gender, + company_name, + address1, + address2, + postcode, + city, + state, + country, + email, + phone, + default_address, + additional, + created_at, + updated_at + ) + SELECT + "customer", + customer_id, + first_name, + last_name, + (SELECT gender FROM customers c WHERE c.id=ca.customer_id), + company_name, + address1, + address2, + postcode, + city, + state, + country, + null, + phone, + default_address, + JSON_INSERT('{}', '$.old_customer_address_id', id), + created_at, + updated_at + FROM customer_addresses ca; +SQL; + + DB::unprepared($insertCustomerAddresses); + } + + private function migrateCartAddresses(): void + { + $dbPrefix = DB::getTablePrefix(); + + $insertCustomerAddresses = <<< SQL + INSERT INTO ${dbPrefix}addresses( + address_type, + customer_id, + cart_id, + first_name, + last_name, + gender, + company_name, + address1, + address2, + postcode, + city, + state, + country, + email, + phone, + additional, + created_at, + updated_at + ) + SELECT + (CASE WHEN ca.address_type='billing' THEN "cart_billing" ELSE "cart_shipping" END), + customer_id, + cart_id, + first_name, + last_name, + (SELECT gender FROM customers c WHERE c.id=ca.customer_id), + company_name, + address1, + address2, + postcode, + city, + state, + country, + email, + phone, + JSON_INSERT('{}', '$.old_cart_address_id', id), + created_at, + updated_at + FROM cart_address ca; +SQL; + + DB::unprepared($insertCustomerAddresses); + } + + private function migrateOrderAddresses(): void + { + $dbPrefix = DB::getTablePrefix(); + + $insertCustomerAddresses = <<< SQL + INSERT INTO ${dbPrefix}addresses( + address_type, + customer_id, + order_id, + first_name, + last_name, + gender, + company_name, + address1, + address2, + postcode, + city, + state, + country, + email, + phone, + additional, + created_at, + updated_at + ) + SELECT + (CASE WHEN oa.address_type='billing' THEN "order_billing" ELSE "order_shipping" END), + customer_id, + order_id, + first_name, + last_name, + (SELECT gender FROM customers c WHERE c.id=oa.customer_id), + company_name, + address1, + address2, + postcode, + city, + state, + country, + email, + phone, + JSON_INSERT('{}', '$.old_order_address_id', id), + created_at, + updated_at + FROM order_address oa; +SQL; + + DB::unprepared($insertCustomerAddresses); + } + + private function migrateForeignKeys(): void + { + Schema::table('cart_shipping_rates', static function (Blueprint $table) { + $table->dropForeign(['cart_address_id']); + + CartAddress::query() + ->orderBy('id', 'asc') // for some reason each() needs an orderBy in before + ->each(static function ($row) { + CartShippingRate::query() + ->where('cart_address_id', $row->additional['old_cart_address_id']) + ->update(['cart_address_id' => $row->id]); + }); + + $table->foreign(['cart_address_id']) + ->references('id') + ->on('addresses') + ->onDelete('cascade'); + }); + + Schema::table('invoices', static function (Blueprint $table) { + $table->dropForeign(['order_address_id']); + + OrderAddress::query() + ->orderBy('id', 'asc') // for some reason each() needs an orderBy in before + ->each(static function ($row) { + Invoice::query() + ->where('order_address_id', $row->additional['old_order_address_id']) + ->update(['order_address_id' => $row->id]); + }); + + $table->foreign(['order_address_id']) + ->references('id') + ->on('addresses') + ->onDelete('cascade'); + }); + + Schema::table('shipments', static function (Blueprint $table) { + $table->dropForeign(['order_address_id']); + + OrderAddress::query() + ->orderBy('id', 'asc') // for some reason each() needs an orderBy in before + ->each(static function ($row) { + Shipment::query() + ->where('order_address_id', $row->additional['old_order_address_id']) + ->update(['order_address_id' => $row->id]); + }); + + $table->foreign(['order_address_id']) + ->references('id') + ->on('addresses') + ->onDelete('cascade'); + }); + } +} diff --git a/packages/Webkul/Core/src/Models/Address.php b/packages/Webkul/Core/src/Models/Address.php new file mode 100644 index 000000000..9b0d68e97 --- /dev/null +++ b/packages/Webkul/Core/src/Models/Address.php @@ -0,0 +1,91 @@ + 'array', + ]; + + /** + * Get all of the attributes for the attribute groups. + */ + public function getNameAttribute(): string + { + return $this->first_name . ' ' . $this->last_name; + } + + /** + * Get the customer record associated with the address. + */ + public function customer(): BelongsTo + { + return $this->belongsTo(Customer::class); + } +} diff --git a/packages/Webkul/Customer/src/Database/Factories/CustomerAddressFactory.php b/packages/Webkul/Customer/src/Database/Factories/CustomerAddressFactory.php index e60f5fe88..877df08e2 100644 --- a/packages/Webkul/Customer/src/Database/Factories/CustomerAddressFactory.php +++ b/packages/Webkul/Customer/src/Database/Factories/CustomerAddressFactory.php @@ -7,8 +7,6 @@ use Webkul\Customer\Models\Customer; use Webkul\Customer\Models\CustomerAddress; $factory->define(CustomerAddress::class, function (Faker $faker) { - $now = date("Y-m-d H:i:s"); - // use an locale from a country in europe so the vat id can be generated $fakerIt = \Faker\Factory::create('it_IT'); @@ -27,8 +25,7 @@ $factory->define(CustomerAddress::class, function (Faker $faker) { 'postcode' => $faker->postcode, 'phone' => $faker->e164PhoneNumber, 'default_address' => array_random([0, 1]), - 'created_at' => $now, - 'updated_at' => $now, + 'address_type' => CustomerAddress::ADDRESS_TYPE, ]; }); diff --git a/packages/Webkul/Customer/src/Models/CustomerAddress.php b/packages/Webkul/Customer/src/Models/CustomerAddress.php index 389857a53..89cecb4cb 100755 --- a/packages/Webkul/Customer/src/Models/CustomerAddress.php +++ b/packages/Webkul/Customer/src/Models/CustomerAddress.php @@ -2,34 +2,32 @@ namespace Webkul\Customer\Models; -use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Builder; +use Webkul\Core\Models\Address; use Webkul\Customer\Contracts\CustomerAddress as CustomerAddressContract; -class CustomerAddress extends Model implements CustomerAddressContract +class CustomerAddress extends Address implements CustomerAddressContract { - protected $table = 'customer_addresses'; + public const ADDRESS_TYPE = 'customer'; - protected $fillable = [ - 'customer_id', - 'company_name', - 'vat_id', - 'address1', - 'address2', - 'country', - 'state', - 'city', - 'postcode', - 'phone', - 'default_address', - 'first_name', - 'last_name', + /** + * @var array default values + */ + protected $attributes = [ + 'address_type' => self::ADDRESS_TYPE, ]; /** - * Get the customer address full name. + * The "booted" method of the model. + * + * @return void */ - public function getNameAttribute() + protected static function boot() { - return $this->first_name . ' ' . $this->last_name; + static::addGlobalScope('address_type', static function (Builder $builder) { + $builder->where('address_type', self::ADDRESS_TYPE); + }); + + parent::boot(); } } diff --git a/packages/Webkul/Sales/src/Database/Factories/OrderAddressFactory.php b/packages/Webkul/Sales/src/Database/Factories/OrderAddressFactory.php index 12f1004f6..d8b44c4bc 100644 --- a/packages/Webkul/Sales/src/Database/Factories/OrderAddressFactory.php +++ b/packages/Webkul/Sales/src/Database/Factories/OrderAddressFactory.php @@ -10,7 +10,7 @@ use Webkul\Sales\Models\OrderAddress; $factory->define(OrderAddress::class, function (Faker $faker) { $customer = factory(Customer::class)->create(); - $customerAddress = factory(CustomerAddress::class)->create(); + $customerAddress = factory(CustomerAddress::class)->make(); return [ 'first_name' => $customer->first_name, @@ -22,7 +22,7 @@ $factory->define(OrderAddress::class, function (Faker $faker) { 'city' => $customerAddress->city, 'postcode' => $customerAddress->postcode, 'phone' => $customerAddress->phone, - 'address_type' => 'billing', + 'address_type' => OrderAddress::ADDRESS_TYPE_BILLING, 'order_id' => function () { return factory(Order::class)->create()->id; }, @@ -30,5 +30,5 @@ $factory->define(OrderAddress::class, function (Faker $faker) { }); $factory->state(OrderAddress::class, 'shipping', [ - 'address_type' => 'shipping', + 'address_type' => OrderAddress::ADDRESS_TYPE_SHIPPING, ]); \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Models/Invoice.php b/packages/Webkul/Sales/src/Models/Invoice.php index 127ddfaf4..65d9a850a 100755 --- a/packages/Webkul/Sales/src/Models/Invoice.php +++ b/packages/Webkul/Sales/src/Models/Invoice.php @@ -34,7 +34,8 @@ class Invoice extends Model implements InvoiceContract /** * Get the invoice items record associated with the invoice. */ - public function items() { + public function items() + { return $this->hasMany(InvoiceItemProxy::modelClass())->whereNull('parent_id'); } @@ -55,10 +56,11 @@ class Invoice extends Model implements InvoiceContract } /** - * Get the addresses for the shipment. + * Get the address for the invoice. */ public function address() { - return $this->belongsTo(OrderAddressProxy::modelClass(), 'order_address_id'); + return $this->belongsTo(OrderAddressProxy::modelClass(), 'order_address_id') + ->where('address_type', OrderAddress::ADDRESS_TYPE_BILLING); } } \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Models/Order.php b/packages/Webkul/Sales/src/Models/Order.php index 48d5725de..bd6eaf01b 100755 --- a/packages/Webkul/Sales/src/Models/Order.php +++ b/packages/Webkul/Sales/src/Models/Order.php @@ -8,6 +8,14 @@ use Webkul\Sales\Contracts\Order as OrderContract; class Order extends Model implements OrderContract { + public const STATUS_PENDING = 'pending'; + public const STATUS_PENDING_PAYMENT = 'pending_payment'; + public const STATUS_PROCESSING = 'processing'; + public const STATUS_COMPLETED = 'completed'; + public const STATUS_CANCELED = 'canceled'; + public const STATUS_CLOSED = 'closed'; + public const STATUS_FRAUD = 'fraud'; + protected $guarded = [ 'id', 'items', @@ -21,13 +29,13 @@ class Order extends Model implements OrderContract ]; protected $statusLabel = [ - 'pending' => 'Pending', - 'pending_payment' => 'Pending Payment', - 'processing' => 'Processing', - 'completed' => 'Completed', - 'canceled' => 'Canceled', - 'closed' => 'Closed', - 'fraud' => 'Fraud', + self::STATUS_PENDING => 'Pending', + self::STATUS_PENDING_PAYMENT => 'Pending Payment', + self::STATUS_PROCESSING => 'Processing', + self::STATUS_COMPLETED => 'Completed', + self::STATUS_CANCELED => 'Canceled', + self::STATUS_CLOSED => 'Closed', + self::STATUS_FRAUD => 'Fraud', ]; /** @@ -140,7 +148,7 @@ class Order extends Model implements OrderContract */ public function billing_address() { - return $this->addresses()->where('address_type', 'billing'); + return $this->addresses()->where('address_type', OrderAddress::ADDRESS_TYPE_BILLING); } /** @@ -156,7 +164,7 @@ class Order extends Model implements OrderContract */ public function shipping_address() { - return $this->addresses()->where('address_type', 'shipping'); + return $this->addresses()->where('address_type', OrderAddress::ADDRESS_TYPE_SHIPPING); } /** @@ -180,7 +188,7 @@ class Order extends Model implements OrderContract * * @return boolean */ - public function haveStockableItems() + public function haveStockableItems(): bool { foreach ($this->items as $item) { if ($item->getTypeInstance()->isStockable()) { @@ -193,10 +201,12 @@ class Order extends Model implements OrderContract /** * Checks if new shipment is allow or not + * + * @return bool */ - public function canShip() + public function canShip(): bool { - if ($this->status == 'fraud') { + if ($this->status === self::STATUS_FRAUD) { return false; } @@ -211,10 +221,12 @@ class Order extends Model implements OrderContract /** * Checks if new invoice is allow or not + * + * @return bool */ - public function canInvoice() + public function canInvoice(): bool { - if ($this->status == 'fraud') { + if ($this->status === self::STATUS_FRAUD) { return false; } @@ -229,10 +241,12 @@ class Order extends Model implements OrderContract /** * Checks if order can be canceled or not + * + * @return bool */ - public function canCancel() + public function canCancel(): bool { - if ($this->status == 'fraud') { + if ($this->status === self::STATUS_FRAUD) { return false; } @@ -247,10 +261,12 @@ class Order extends Model implements OrderContract /** * Checks if order can be refunded or not + * + * @return bool */ - public function canRefund() + public function canRefund(): bool { - if ($this->status == 'fraud') { + if ($this->status === self::STATUS_FRAUD) { return false; } diff --git a/packages/Webkul/Sales/src/Models/OrderAddress.php b/packages/Webkul/Sales/src/Models/OrderAddress.php index d1bcddc62..a8a63f700 100755 --- a/packages/Webkul/Sales/src/Models/OrderAddress.php +++ b/packages/Webkul/Sales/src/Models/OrderAddress.php @@ -2,47 +2,64 @@ namespace Webkul\Sales\Models; -use Illuminate\Database\Eloquent\Model; -use Webkul\Customer\Models\Customer; +use Webkul\Checkout\Models\CartAddress; +use Webkul\Core\Models\Address; use Webkul\Sales\Contracts\OrderAddress as OrderAddressContract; +use Illuminate\Database\Eloquent\Builder; -class OrderAddress extends Model implements OrderAddressContract +/** + * Class OrderAddress + * @package Webkul\Sales\Models + * + * @property integer $order_id + * @property Order $order + * + */ +class OrderAddress extends Address implements OrderAddressContract { - protected $table = 'order_address'; + public const ADDRESS_TYPE_SHIPPING = 'order_shipping'; + public const ADDRESS_TYPE_BILLING = 'order_billing'; - protected $guarded = ['id', 'created_at', 'updated_at']; - - protected $fillable = [ - 'first_name', - 'last_name', - 'email', - 'company_name', - 'vat_id', - 'address1', - 'address2', - 'city', - 'state', - 'postcode', - 'country', - 'phone', - 'address_type', - 'cart_id', - 'customer_id', + /** + * @var array default values + */ + protected $attributes = [ + 'address_type' => self::ADDRESS_TYPE_BILLING, ]; /** - * Get of the customer fullname. + * The "booted" method of the model. + * + * @return void */ - public function getNameAttribute() + protected static function boot() { - return $this->first_name . ' ' . $this->last_name; + static::addGlobalScope('address_type', function (Builder $builder) { + $builder->whereIn('address_type', [ + self::ADDRESS_TYPE_BILLING, + self::ADDRESS_TYPE_SHIPPING + ]); + }); + + static::creating(static function ($address) { + switch ($address->address_type) { + case CartAddress::ADDRESS_TYPE_BILLING: + $address->address_type = self::ADDRESS_TYPE_BILLING; + break; + case CartAddress::ADDRESS_TYPE_SHIPPING: + $address->address_type = self::ADDRESS_TYPE_SHIPPING; + break; + } + }); + + parent::boot(); } /** - * Get the customer record associated with the order. + * Get the order record associated with the address. */ - public function customer() + public function order() { - return $this->belongsTo(Customer::class); + return $this->belongsTo(Order::class); } } \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Models/Shipment.php b/packages/Webkul/Sales/src/Models/Shipment.php index 1627100a5..8dc2cbb87 100755 --- a/packages/Webkul/Sales/src/Models/Shipment.php +++ b/packages/Webkul/Sales/src/Models/Shipment.php @@ -47,10 +47,11 @@ class Shipment extends Model implements ShipmentContract } /** - * Get the addresses for the shipment. + * Get the address for the shipment. */ public function address() { - return $this->belongsTo(OrderAddressProxy::modelClass(), 'order_address_id'); + return $this->belongsTo(OrderAddressProxy::modelClass(), 'order_address_id') + ->where('address_type', OrderAddress::ADDRESS_TYPE_SHIPPING); } } \ No newline at end of file diff --git a/packages/Webkul/Shipping/src/Carriers/FlatRate.php b/packages/Webkul/Shipping/src/Carriers/FlatRate.php index 5cbf59083..6170bce6b 100755 --- a/packages/Webkul/Shipping/src/Carriers/FlatRate.php +++ b/packages/Webkul/Shipping/src/Carriers/FlatRate.php @@ -23,7 +23,7 @@ class FlatRate extends AbstractShipping /** * Returns rate for flatrate * - * @return array + * @return CartShippingRate|false */ public function calculate() { diff --git a/packages/Webkul/Shipping/src/Carriers/Free.php b/packages/Webkul/Shipping/src/Carriers/Free.php index f03247c94..c3c0e0ec5 100755 --- a/packages/Webkul/Shipping/src/Carriers/Free.php +++ b/packages/Webkul/Shipping/src/Carriers/Free.php @@ -22,7 +22,7 @@ class Free extends AbstractShipping /** * Returns rate for flatrate * - * @return array + * @return CartShippingRate|false */ public function calculate() { diff --git a/tests/functional/Checkout/Order/OrderCest.php b/tests/functional/Checkout/Order/OrderCest.php index 2cf903895..8d7e47f13 100644 --- a/tests/functional/Checkout/Order/OrderCest.php +++ b/tests/functional/Checkout/Order/OrderCest.php @@ -67,13 +67,13 @@ class OrderCest $I->seeResponseCodeIsSuccessful(); $I->seeRecord(CartAddress::class, array_merge($addressData, [ - 'address_type' => 'shipping', + 'address_type' => CartAddress::ADDRESS_TYPE_SHIPPING, 'cart_id' => $mocks['cart']->id, 'customer_id' => $mocks['customer']->id, ])); $I->seeRecord(CartAddress::class, array_merge($addressData, [ - 'address_type' => 'billing', + 'address_type' => CartAddress::ADDRESS_TYPE_BILLING, 'cart_id' => $mocks['cart']->id, 'customer_id' => $mocks['customer']->id, ])); @@ -128,13 +128,13 @@ class OrderCest $I->seeRecord(OrderAddress::class, array_merge($addressData, [ 'order_id' => $order->id, - 'address_type' => 'shipping', + 'address_type' => OrderAddress::ADDRESS_TYPE_SHIPPING, 'customer_id' => $mocks['customer']->id, ])); $I->seeRecord(OrderAddress::class, array_merge($addressData, [ 'order_id' => $order->id, - 'address_type' => 'billing', + 'address_type' => OrderAddress::ADDRESS_TYPE_BILLING, 'customer_id' => $mocks['customer']->id, ])); diff --git a/tests/unit/Core/AddressCest.php b/tests/unit/Core/AddressCest.php new file mode 100644 index 000000000..ecc0bd8be --- /dev/null +++ b/tests/unit/Core/AddressCest.php @@ -0,0 +1,108 @@ +have(CartAddress::class); + $customerAddress = $I->have(CustomerAddress::class); + $orderAddress = $I->have(OrderAddress::class); + + $cartAddresses = CartAddress::all(); + $I->assertCount(1, $cartAddresses); + $I->assertEquals($cartAddress->id, $cartAddresses[0]->id); + + $customerAddresses = CustomerAddress::all(); + $I->assertCount(1, $customerAddresses); + $I->assertEquals($customerAddress->id, $customerAddresses[0]->id); + + $orderAddresses = OrderAddress::all(); + $I->assertCount(1, $orderAddresses); + $I->assertEquals($orderAddress->id, $orderAddresses[0]->id); + } + + public function testCustomerAddressRelations(UnitTester $I): void + { + /** @var Customer $customer1 */ + $customer1 = $I->have(Customer::class); + CustomerAddress::create(['customer_id' => $customer1->id]); + + /** @var Customer $customer2 */ + $customer2 = $I->have(Customer::class); + $address1 = CustomerAddress::create(['customer_id' => $customer2->id]); + + $customer2->refresh(); + $I->assertCount(1, $customer2->addresses); + $I->assertEquals($address1->id, $customer2->addresses[0]->id); + $I->assertNull($customer2->default_address); + + $address2 = CustomerAddress::create(['customer_id' => $customer2->id, 'default_address' => true]); + $customer2->refresh(); + $I->assertCount(2, $customer2->addresses); + $I->assertEquals($address2->id, $customer2->default_address->id); + } + + public function testCartAddressRelations(UnitTester $I): void + { + /** @var Cart $cart */ + $cart = $I->have(Cart::class); + $address1 = CartAddress::create(['cart_id' => $cart->id]); + $address2 = CartAddress::create([ + 'cart_id' => $cart->id, + 'address_type' => CartAddress::ADDRESS_TYPE_SHIPPING + ]); + $cart->refresh(); + + $I->assertNotNull($address1->address_type); + $I->assertEquals($address1->id, $cart->billing_address->id); + $I->assertEquals($address2->id, $cart->shipping_address->id); + + /** @var CartShippingRate $freeShipping */ + $freeShipping = (new Free())->calculate(); + $freeShipping->cart_address_id = $address2->id; + $freeShipping->saveOrFail(); + + $freeShipping->refresh(); + $I->assertEquals($address2->id, $freeShipping->shipping_address->id); + } + + public function testOrderAddressRelations(UnitTester $I): void + { + /** @var Order $order */ + $order = $I->have(Order::class); + $address1 = OrderAddress::create(['order_id' => $order->id]); + $address2 = OrderAddress::create([ + 'order_id' => $order->id, + 'address_type' => OrderAddress::ADDRESS_TYPE_SHIPPING + ]); + $order->refresh(); + + $I->assertNotNull($address1->address_type); + $I->assertEquals($address1->id, $order->billing_address->id); + $I->assertEquals($address2->id, $order->shipping_address->id); + + /** @var Shipment $shipment */ + $shipment = Shipment::create(['order_address_id' => $address2->id]); + $I->assertEquals($address2->id, $shipment->address->id); + + /** @var Invoice $invoice */ + $invoice = Invoice::create(['order_id' => $order->id, 'order_address_id' => $address1->id]); + $I->assertEquals($address1->id, $invoice->address->id); + } +} \ No newline at end of file