Merge pull request #2910 from Haendlerbund/unified-addresses

Unified addresses (#2902)
This commit is contained in:
Jitendra Singh 2020-04-22 17:05:57 +05:30 committed by GitHub
commit 7629d85d16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 671 additions and 128 deletions

View File

@ -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) {

View File

@ -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'))

View File

@ -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'));

View File

@ -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')

View File

@ -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]));
}
}
}

View File

@ -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,
];
});

View File

@ -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);
}
/**

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,294 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Webkul\Checkout\Models\CartAddress;
use Webkul\Checkout\Models\CartShippingRate;
use Webkul\Sales\Models\Invoice;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Sales\Models\Shipment;
class AddTableAddresses extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
try {
// transaction is important to prevent loosing data on failure
DB::beginTransaction();
Schema::create('addresses', function (Blueprint $table) {
$table->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');
});
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace Webkul\Core\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Webkul\Customer\Models\Customer;
/**
* Class Address
* @package Webkul\Core\Models
*
* @property string $address_type
* @property integer $customer_id
* @property Customer $customer
* @property string $first_name
* @property string $last_name
* @property string $gender
* @property string $company_name
* @property string $address1
* @property string $address2
* @property string $postcode
* @property string $city
* @property string $state
* @property string $country
* @property string $email
* @property string $phone
* @property boolean $default_address
* @property array $additional
*
* @property-read integer $id
* @property-read string $name
* @property-read Carbon $created_at
* @property-read Carbon $updated_at
*
*/
abstract class Address extends Model
{
protected $table = 'addresses';
protected $guarded = [
'id',
'created_at',
'updated_at',
];
protected $fillable = [
'address_type',
'customer_id',
'cart_id',
'order_id',
'first_name',
'last_name',
'gender',
'company_name',
'address1',
'address2',
'postcode',
'city',
'state',
'country',
'email',
'phone',
'default_address',
'vat_id',
'additional',
];
protected $casts = [
'additional' => '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);
}
}

View File

@ -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,
];
});

View File

@ -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();
}
}

View File

@ -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,
]);

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -23,7 +23,7 @@ class FlatRate extends AbstractShipping
/**
* Returns rate for flatrate
*
* @return array
* @return CartShippingRate|false
*/
public function calculate()
{

View File

@ -22,7 +22,7 @@ class Free extends AbstractShipping
/**
* Returns rate for flatrate
*
* @return array
* @return CartShippingRate|false
*/
public function calculate()
{

View File

@ -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,
]));

View File

@ -0,0 +1,108 @@
<?php
namespace Tests\Unit\Core;
use UnitTester;
use Webkul\Checkout\Models\Cart;
use Webkul\Checkout\Models\CartAddress;
use Webkul\Checkout\Models\CartShippingRate;
use Webkul\Customer\Models\Customer;
use Webkul\Customer\Models\CustomerAddress;
use Webkul\Sales\Models\Invoice;
use Webkul\Sales\Models\Order;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Sales\Models\Shipment;
use Webkul\Shipping\Carriers\Free;
class AddressCest
{
public function testAddressFilters(UnitTester $I): void
{
$cartAddress = $I->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);
}
}