阶段更新

This commit is contained in:
2023-01-12 14:47:38 +08:00
parent 088dd64b2f
commit 5b8901281c
626 changed files with 39326 additions and 12 deletions

View File

@@ -0,0 +1,20 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\HasCovers;
use App\Traits\HasStatus;
class Activity extends Model
{
use HasStatus,HasCovers;
public $status_map = [
0 => '关闭',
1 => '正常',
];
protected $table = 'mall_activities';
}

View File

@@ -0,0 +1,86 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\HasRegion;
use Modules\User\Traits\BelongsToUser;
use Overtrue\LaravelVersionable\Versionable;
class Address extends Model
{
use BelongsToUser,
HasRegion,
Versionable,
SoftDeletes;
protected $table = 'mall_addresses';
protected $casts = [
'is_default' => 'boolean',
];
/**
* 不参与版本记录的字段
* @var array|string[]
*/
protected array $dontVersionable = ['updated_at'];
/**
* @var array
*/
protected $guarded = [
'created_at',
'updated_at',
];
public static function boot()
{
parent::boot();
/**
* 如果当前地址为默认地址,取消其他地址的默认地址设置
*/
self::saved(function ($model) {
if ($model->is_default && $model->id) {
Address::where('id', '<>', $model->id)
->where('user_id', $model->user_id)
->where('is_default', 1)
->update(['is_default' => 0]);
}
// else {
// Address::where('user_id', $model->user_id)
// ->where('is_default', 1)
// ->update(['is_default' => 0]);
// }
});
}
/**
* Notes: 保存默认地址时转换格式,非0的都转换成0
* @Author: <C.Jason>
* @Date : 2020/11/5 5:23 下午
* @param $value
*/
protected function setIsDefaultAttribute($value): void
{
if (strtolower($value) === 'false' || $value === '0') {
$this->attributes['is_default'] = 0;
} else {
$this->attributes['is_default'] = !!$value;
}
}
/**
* Notes : 将地址设置为默认地址
* @Date : 2021/4/23 1:34 下午
* @Author : < Jason.C >
*/
public function setDefault(): void
{
$this->is_default = 1;
$this->save();
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\HasCovers;
use App\Traits\WithPosition;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Linker\Traits\HasLinker;
use Modules\Mall\Models\Traits\BelongsToShop;
class Banner extends Model
{
use BelongsToShop,
Cachable,
HasCovers,
SoftDeletes,
HasLinker,
WithPosition;
const POSITION_INDEX = 1;
const POSITION_INDEX_CENTER = 2;
public array $position_map = [
self::POSITION_INDEX => '首页顶部',
self::POSITION_INDEX_CENTER => '体检官介绍',
];
protected $table = 'mall_banners';
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\BelongsToShop;
use Overtrue\LaravelVersionable\Versionable;
class Brand extends Model
{
use BelongsToShop,
Cachable,
Versionable,
SoftDeletes;
protected $table = 'mall_brands';
/**
* 不参与版本记录的字段
* @var array|string[]
*/
protected array $dontVersionable = ['updated_at'];
/**
* Notes : 品牌下的商品
* @Date : 2021/5/25 12:05 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function goods(): HasMany
{
return $this->hasMany(Goods::class);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Modules\Mall\Models\Traits\BelongsToShop;
use Modules\User\Traits\BelongsToUser;
class Cart extends Model
{
use BelongsToShop,
BelongsToUser;
protected $table = 'mall_carts';
/**
* Notes : 购物车商品
* @Date : 2021/5/13 2:25 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function sku(): BelongsTo
{
return $this->belongsTo(GoodsSku::class, 'sku_id');
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\HasCovers;
use App\Traits\HasStatus;
use App\Traits\OrderByOrderAsc;
use Encore\Admin\Traits\AdminBuilder;
use Encore\Admin\Traits\ModelTree;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\BelongsToShop;
use Overtrue\LaravelVersionable\Versionable;
class Category extends Model
{
use AdminBuilder,
BelongsToShop,
Cachable,
HasCovers,
ModelTree,
OrderByOrderAsc,
HasStatus,
Versionable,
SoftDeletes;
protected $table = 'mall_categories';
/**
* 不参与版本记录的字段
* @var array|string[]
*/
protected array $dontVersionable = ['updated_at'];
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->setTitleColumn('name');
}
/**
* Notes : 分类商品
* @Date : 2021/5/12 9:49 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function goods(): HasMany
{
return $this->hasMany(Goods::class);
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\BelongsToShop;
class Delivery extends Model
{
use BelongsToShop,
Cachable,
SoftDeletes;
protected $table = 'mall_deliveries';
const TYPE_BY_COUNT = 1;
const TYPE_BY_WEIGHT = 2;
const TYPE_MAP = [
self::TYPE_BY_COUNT => '按数量',
self::TYPE_BY_WEIGHT => '按重量',
];
/**
* Notes : 模板对应的规则
* @Date : 2021/3/15 1:11 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function rules(): HasMany
{
return $this->hasMany(DeliveryRule::class);
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class DeliveryRule extends Model
{
use SoftDeletes;
protected $table = 'mall_delivery_rules';
protected $casts = [
'regions' => 'json',
];
/**
* Notes : 隶属的模板
* @Date : 2021/3/15 1:12 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function delivery(): BelongsTo
{
return $this->belongsTo(Delivery::class);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\HasCovers;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Express extends Model
{
use Cachable,
HasCovers,
SoftDeletes;
protected $table = 'mall_expresses';
/**
* Notes : 使用该物流的公司
* @Date : 2021/5/6 5:23 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function shops(): BelongsToMany
{
return $this->belongsToMany(Shop::class, 'mall_shop_express')
->withTimestamps();
}
}

View File

@@ -0,0 +1,267 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\HasClicks;
use App\Traits\HasCovers;
use App\Traits\HasStatus;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;
use Modules\Mall\Models\Traits\BelongsToShop;
use Overtrue\LaravelVersionable\Versionable;
class Goods extends Model
{
use BelongsToShop,
HasStatus,
HasClicks,
HasCovers,
Versionable,
SoftDeletes;
/**
* 规格,支持单规格和多规格
*/
const TYPE_SINGLE = 1;
const TYPE_MULTIPLE = 2;
const TYPE_MAP = [
self::TYPE_SINGLE => '单规格',
// self::TYPE_MULTIPLE => '多规格',
];
/**
* 状态
*/
const STATUS_AUDIT = 0;
const STATUS_UP = 1;
const STATUS_REJECT = 2;
const STATUS_DOWN = 3;
const STATUS_MAP = [
self::STATUS_AUDIT => '审核中',
self::STATUS_UP => '上架',
self::STATUS_REJECT => '驳回',
self::STATUS_DOWN => '下架',
];
/**
* 库存的扣减方式
*/
const DEDUCT_STOCK_ORDER = 1;
const DEDUCT_STOCK_PAID = 2;
const DEDUCT_STOCK_MAP = [
self::DEDUCT_STOCK_ORDER => '下单减库存',
self::DEDUCT_STOCK_PAID => '付款减库存',
];
/**
* 支付方式
*/
const PAY_TYPE_ONLINE = 1;
const PAY_TYPE_OFFLINE = 2;
const PAY_TYPE_ALL = 3;
const PAY_TYPE_MAP = [
self::PAY_TYPE_ONLINE => '在线支付',
self::PAY_TYPE_OFFLINE => '货到付款',
self::PAY_TYPE_ALL => '在线支付/货到付款',
];
/**
* 商品类型
*/
const CHANNEL_NORMAL = 1;
const CHANNEL_SCORE = 2;
const CHANNEL_FREE = 3;
const Channels = [
self::CHANNEL_NORMAL => '正常',
self::CHANNEL_SCORE => '积分兑换',
self::CHANNEL_FREE => '赠送',
];
/**
* 展示列表,从数据库查询的字段
*/
const LIST_SELECT_FIELDS = [
'id',
'name',
'description',
'cover',
'shop_id',
'original_price',
'sales',
'clicks',
];
protected $table = 'mall_goods';
protected $casts = [
'pictures' => 'json',
];
protected $with = [
'specs',
'skus',
];
/**
* 不参与版本记录的字段
*
* @var array|string[]
*/
protected array $dontVersionable = ['clicks', 'updated_at'];
/**
* Notes : 商品分类
*
* @Date : 2021/5/12 9:48 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
/**
* Notes : 标签
*
* @Date : 2021/5/12 10:14 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class, 'mall_goods_tag');
}
/**
* Notes : 所属品牌
*
* @Date : 2021/5/11 11:00 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function brand(): BelongsTo
{
return $this->belongsTo(Brand::class);
}
/**
* Notes : 运费模板
*
* @Date : 2021/5/11 11:04 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function delivery(): BelongsTo
{
return $this->belongsTo(Delivery::class);
}
/**
* Notes : 商品属性
*
* @Date : 2021/5/12 11:31 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function specs(): HasMany
{
return $this->hasMany(GoodsSpec::class);
}
/**
* Notes : 商品SKU
*
* @Date : 2021/5/11 1:47 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function skus(): HasMany
{
return $this->hasMany(GoodsSku::class);
}
/**
* Notes : 获取规格的价格区间
*
* @Date : 2021/5/13 11:49 上午
* @Author : < Jason.C >
* @return string
*/
public function getPriceAttribute(): string
{
if ($this->type === self::TYPE_SINGLE) {
return $this->price_min;
} else {
return $this->price_min.'|'.$this->price_max;
}
}
/**
* Notes : 返回最低积分
*
* @Date : 2021/5/20 11:26 上午
* @Author : < Jason.C >
* @return float
*/
public function getScoreAttribute(): float
{
return $this->skus->min('score') ?? 0;
}
/**
* Notes : 最低价格
*
* @Date : 2021/5/13 11:50 上午
* @Author : < Jason.C >
* @return float
*/
public function getPriceMinAttribute(): float
{
return $this->skus->min('price') ?? 0;
}
/**
* Notes : 最高价格
*
* @Date : 2021/5/13 11:51 上午
* @Author : < Jason.C >
* @return float
*/
public function getPriceMaxAttribute(): float
{
return $this->skus->max('price') ?? 0;
}
/**
* Notes : 按价格排序
*
* @Date : 2021/5/17 14:18
* @Author : Mr.wang
* @param Builder $query
* @param string $direction
* @return Builder
*/
public function scopeOrderByPrice(Builder $query, string $direction = 'asc'): Builder
{
if ($direction) {
$price = DB::raw('MIN(price) as min_price');
} else {
$price = DB::raw('MAX(price) as min_price');
}
$minPrice = DB::table('mall_goods_skus')
->select('goods_id', $price)
->whereNull('deleted_at')
->groupBy('goods_id');
return $query->joinSub($minPrice, 'min_price', function ($join) {
$join->on('mall_goods.id', '=', 'min_price.goods_id');
})->orderBy('min_price', $direction);
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\HasCovers;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\GoodsAttribute;
use Overtrue\LaravelVersionable\Versionable;
class GoodsSku extends Model
{
use HasCovers,
Versionable,
GoodsAttribute,
SoftDeletes;
protected $table = 'mall_goods_skus';
/**
* 不参与版本记录的字段
*
* @var array|string[]
*/
protected array $dontVersionable = ['updated_at'];
/**
* Notes : 所属品牌
*
* @Date : 2021/5/11 11:00 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function goods(): BelongsTo
{
return $this->belongsTo(Goods::class);
}
/**
* Notes : 当前规格是否可购买
*
* @Date : 2021/5/14 10:08
* @Author : Mr.wang
* @param int $qty
* @return bool
*/
public function canBuy(int $qty = 1): bool
{
if ($this->goods->channel == Goods::CHANNEL_FREE) {
return true;
}
if ($this->goods->status == Goods::STATUS_UP && $this->stock >= $qty) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class GoodsSpec extends Model
{
protected $table = 'mall_goods_specs';
/**
* Notes : 所属商品
* @Date : 2021/5/11 4:51 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function goods(): BelongsTo
{
return $this->belongsTo(Goods::class);
}
/**
* Notes : 属性值
* @Date : 2021/5/11 4:52 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function values(): HasMany
{
return $this->hasMany(GoodsSpecValue::class, 'spec_id');
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class GoodsSpecValue extends Model
{
protected $table = 'mall_goods_spec_values';
/**
* Notes : 所属属性
* @Date : 2021/5/11 4:52 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function spec(): BelongsTo
{
return $this->belongsTo(GoodsSpec::class);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\BelongsToShop;
class Job extends Model
{
use BelongsToShop,
Cachable,
SoftDeletes;
protected $table = 'mall_jobs';
}

View File

@@ -0,0 +1,313 @@
<?php
namespace Modules\Mall\Models;
use App\Models\AreaCode;
use App\Models\Model;
use App\Traits\OrderByIdDesc;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\BelongsToShop;
use Modules\Mall\Models\Traits\OrderActions;
use Modules\Mall\Models\Traits\OrderCando;
use Modules\Mall\Models\Traits\OrderScopes;
use Modules\Mall\Traits\WithWorkflow;
use Modules\Payment\Traits\WithPayments;
use Modules\User\Traits\BelongsToUser;
use Overtrue\LaravelVersionable\Versionable;
class Order extends Model
{
use BelongsToUser,
BelongsToShop,
OrderByIdDesc,
OrderCando,
Versionable,
WithWorkflow,
OrderActions,
WithPayments,
OrderScopes,
SoftDeletes;
protected $table = 'mall_orders';
protected $dates = [
'paid_at',
'expired_at',
];
protected $casts = [
'source' => 'json',
];
protected $appends = ['total'];
/**
* 不参与版本记录的字段
*
* @var array|string[]
*/
protected array $dontVersionable = ['updated_at'];
const STATUS_INIT = 'INIT'; // 订单初始化:用户已下单,未付款
const STATUS_CANCEL = 'CANCEL'; // 订单取消:用户未支付并取消订单,超时未支付后自动取消订单
const STATUS_PAID = 'PAID'; // 已支付:用户付款完成,等待发货
const STATUS_DELIVERED = 'DELIVERED'; // 已发货:卖家已发货
const STATUS_SIGNED = 'SIGNED'; // 已签收:用户已签收
const STATUS_COMPLETED = 'COMPLETED'; // 已完成用户签收N天后完成订单不再做任何操作
const REFUND_APPLY = 'REFUND_APPLY'; // 申请退款
const REFUND_AGREE = 'REFUND_AGREE'; // 同意退款
const REFUND_DELIVER = 'REFUND_DELIVER'; // 等待客户退货
const REFUND_DELIVERD = 'REFUND_DELIVERD'; // 客户发货
const REFUND_REFUSE = 'REFUND_REFUSE'; // 拒绝退款
const REFUND_PROCESS = 'REFUND_PROCESS'; // 退款中
const REFUND_COMPLETED = 'REFUND_COMPLETED'; // 退款完成
const STATUS_MAP = [
self::STATUS_INIT => '未付款',
self::STATUS_CANCEL => '已取消',
self::STATUS_PAID => '待发货',
self::STATUS_DELIVERED => '已发货',
self::STATUS_SIGNED => '已签收',
self::STATUS_COMPLETED => '完成',
self::REFUND_APPLY => '申请退款',
self::REFUND_AGREE => '同意退款',
self::REFUND_REFUSE => '拒绝退款',
self::REFUND_DELIVER => '等待退货',
self::REFUND_DELIVERD => '客户退货',
self::REFUND_PROCESS => '退款中',
self::REFUND_COMPLETED => '退款完成',
];
const CANCEL_BY_USER = 2; // 买家取消
const CANCEL_BY_SELLER = 3; // 卖家取消
const CANCEL_BY_SYSTEM = 4; // 系统取消
const TYPE_NORMAL = 1; // 正常
const TYPE_SAMPLE = 2; // 提货
const TYPE_SCORE = 3; // 积分兑换
const TYPE_MAP = [
self::TYPE_NORMAL => '正常',
self::TYPE_SAMPLE => '领取',
self::TYPE_SCORE => '积分兑换',
];
const CHANNEL_USER = 1;
const CHANNEL_SYSTEM = 2;
const CHANNEL_MAP = [
self::CHANNEL_USER => '会员',
self::CHANNEL_SYSTEM => '公司',
];
public static function boot()
{
parent::boot();
self::creating(function ($model) {
$time = explode(' ', microtime());
$counter = $model->whereDate('created_at', Carbon::today())->count() + 1;
$len = config('mall.order_no_counter_length');
$len = $len < 6 ? 6 : $len;
$len = $len > 16 ? 16 : $len;
$model->order_no = date('YmdHis').
sprintf('%06d', $time[0] * 1e6).
sprintf('%0'.$len.'d', $counter);
$model->state = self::STATUS_INIT;
$model->expired_at = Carbon::now()->addMinutes(10);
});
}
/**
* 获取该模型的路由的自定义键名
*
* @return string
*/
public function getRouteKeyName(): string
{
return 'order_no';
}
/**
* Notes : 获取订单总额
*
* @Date : 2021/3/16 1:48 下午
* @Author : < Jason.C >
* @return float
*/
public function getTotalAttribute(): float
{
if ($this->original) {
return sprintf("%.2f", $this->original['amount'] + $this->original['freight']);
}
return sprintf("%.2f", $this->amount + $this->freight);
}
/**
* Notes : 订单状态文本
*
* @Date : 2021/5/10 3:24 下午
* @Author : < Jason.C >
* @return string
*/
public function getStateTextAttribute(): string
{
return self::STATUS_MAP[$this->state];
}
/**
* Notes: 订单类型
*
* @Author: 玄尘
* @Date: 2022/10/13 16:53
* @return string
*/
public function getTypeTextAttribute(): string
{
return self::TYPE_MAP[$this->type];
}
/**
* Notes : 订单发货记录
*
* @Date : 2021/5/11 9:47 上午
* @Author : < Jason.C >
* @return HasOne
*/
public function express(): HasOne
{
return $this->hasOne(OrderExpress::class);
}
/**
* Notes : 订单条目
*
* @Date : 2021/5/11 9:47 上午
* @Author : < Jason.C >
* @return HasMany
*/
public function items(): HasMany
{
return $this->hasMany(OrderItem::class);
}
/**
* Notes: 获取商品
*
* @Author: 玄尘
* @Date : 2021/10/27 15:01
* @return \Illuminate\Database\Eloquent\HigherOrderBuilderProxy|mixed
*/
public function getGoodsAttribute()
{
return $this->items()->first()->source;
}
/**
* Notes : 退款单
*
* @Date : 2021/5/11 9:48 上午
* @Author : < Jason.C >
* @return HasMany
*/
public function refunds(): HasMany
{
return $this->hasMany(Refund::class);
}
/**
* Notes: 获取退款商品数
*
* @Author: 玄尘
* @Date : 2021/5/19 9:50
* @return int
*/
public function getRefundItemsCountAttribute(): int
{
$order_id = $this->id;
return RefundItem::query()
->whereHas('order_item', function ($query) use ($order_id) {
$query->where('order_id', $order_id);
})
->whereHas('refund', function ($query) {
$query->whereNotIN('state', [Refund::REFUND_APPLY]);
})
->count();
}
/**
* Notes : 工作流获取状态
*
* @Date : 2021/5/8 3:52 下午
* @Author : < Jason.C >
* @return string
*/
public function getCurrentState(): string
{
return $this->state;
}
/**
* Notes : 工作流设置状态
*
* @Date : 2021/5/8 4:01 下午
* @Author : < Jason.C >
* @param $state
*/
public function setCurrentState($state)
{
$this->state = $state;
$this->save();
}
/**
* Notes : 当前订单能不能查看物流
*
* @Date : 2021/5/19 11:55
* @Author : Mr.wang
* @return bool
*/
public function getIsLogisticShowAttribute(): bool
{
return in_array($this->state, [
self::STATUS_DELIVERED,
self::STATUS_SIGNED,
self::REFUND_COMPLETED,
]);
}
public function getCanAction(): array
{
return [
'pay' => $this->canPay(),
'cancel' => $this->canCancel(),
'sign' => $this->canSign(),
'refund' => $this->canRefund(),
];
}
/**
* Notes: 提货码
*
* @Author: 玄尘
* @Date: 2023/1/12 14:24
* @return BelongsTo
*/
public function areaCode(): BelongsTo
{
return $this->belongsTo(AreaCode::class);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Modules\Mall\Models\Traits\BelongsToOrder;
use Modules\Mall\Models\Traits\HasRegion;
class OrderExpress extends Model
{
use BelongsToOrder,
HasRegion;
protected $table = 'mall_order_expresses';
protected $dates = [
'deliver_at',
'receive_at',
];
const TYPE_EXPRESS = 1;
const TYPE_LOGISTICS = 2;
const TYPE_MAP = [
self::TYPE_EXPRESS => '快递',
self::TYPE_LOGISTICS => '物流',
];
/**
* Notes : 订单物流信息
*
* @Date : 2021/5/25 12:04 下午
* @Author : < Jason.C >
* @return BelongsTo
*/
public function express(): BelongsTo
{
return $this->belongsTo(Express::class);
}
public function getTypeTextAttribute(): string
{
return self::TYPE_MAP[$this->type];
}
}

View File

@@ -0,0 +1,130 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Modules\Mall\Models\Traits\BelongsToOrder;
class OrderItem extends Model
{
use BelongsToOrder;
protected $table = 'mall_order_items';
const UPDATED_AT = null;
public $casts = [
'source' => 'json',
];
/**
* Notes: 关联商品
*
* @Author: 玄尘
* @Date : 2021/8/11 9:26
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function item(): morphTo
{
return $this->morphTo();
}
/**
* Notes: 关联退款单
*
* @Author: 玄尘
* @Date : 2021/5/19 9:30
*/
public function refund_items(): HasMany
{
return $this->hasMany(RefundItem::class, 'order_item_id');
}
/**
* Notes: 商品状态
*
* @Author: 玄尘
* @Date : 2021/6/17 9:07
*/
public function getRefundStatusTextAttribute()
{
if ($this->isRefund()) {
$refund_item = $this->refund_items()->latest()->first();
if ($refund_item) {
return $refund_item->refund->status_test;
} else {
return '未知状态';
}
} else {
return '正常';
}
}
/**
* Notes: 是否申请退款
*
* @Author: 玄尘
* @Date : 2021/5/21 11:15
*/
public function isRefund(): int
{
return $this->refund_items()->count() > 0;
}
/**
* Notes: 是否可以退款/货
*
* @Author: 玄尘
* @Date : 2021/5/19 9:32
*/
public function canRefund(): bool
{
$can = true;
//是否已申请退款/货
if ($this->isRefund()) {
//最后一个申请
$refundItem = $this->refund_items()->latest()->first();
if ($refundItem && $refundItem->refund->state != Refund::REFUND_REFUSE) {
$can = false;
}
}
$is_post_sale = $this->source['is_post_sale'] ?? 0;
return $is_post_sale && $can && $this->order->can('refund');
}
/**
* Notes: 获取总额
*
* @Author: 玄尘
* @Date : 2021/5/20 13:13
* @return float
*/
public function getTotalAttribute(): float
{
return sprintf("%.2f", $this->price * $this->qty);
}
/**
* Notes: 获取水晶总数
*
* @Author: 玄尘
* @Date : 2021/5/21 11:26
*/
public function getTotalScoreAttribute(): string
{
$score = $this->source['score'] ?? 0;
return sprintf("%.2f", $score * $this->qty);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Reason extends Model
{
use Cachable,
SoftDeletes;
protected $table = 'mall_reasons';
/**
* Notes: 关联店铺
* @Author: 玄尘
* @Date : 2021/5/18 15:28
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function shops(): BelongsToMany
{
return $this->belongsToMany(Shop::class, 'mall_shop_reasons')
->withTimestamps();
}
}

View File

@@ -0,0 +1,216 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\OrderByIdDesc;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\BelongsToOrder;
use Modules\Mall\Models\Traits\BelongsToShop;
use Modules\Mall\Models\Traits\RefundActions;
use Modules\Mall\Traits\WithWorkflow;
use Modules\User\Traits\BelongsToUser;
use Overtrue\LaravelVersionable\Versionable;
class Refund extends Model
{
use BelongsToOrder,
BelongsToShop,
BelongsToUser,
OrderByIdDesc,
Versionable,
WithWorkflow,
RefundActions,
SoftDeletes;
protected $table = 'mall_refunds';
/**
* 不参与版本记录的字段
* @var array|string[]
*/
protected array $dontVersionable = ['updated_at'];
const REFUND_APPLY = 'REFUND_APPLY'; // 申请退款
const REFUND_AGREE = 'REFUND_AGREE'; // 同意退款
const REFUND_REFUSE = 'REFUND_REFUSE'; // 拒绝退款
const REFUND_PROCESS = 'REFUND_PROCESS'; // 退款中
const REFUND_DELIVER = 'REFUND_DELIVER'; // 客户退货,等待签收
const REFUND_DELIVERED = 'REFUND_DELIVERED'; // 客户退货,等待签收
const REFUND_SIGNED = 'REFUND_SIGNED'; // 已签收
const REFUND_COMPLETED = 'REFUND_COMPLETED'; // 退款完成
const STATUS_MAP = [
self::REFUND_APPLY => '申请退款',
self::REFUND_AGREE => '同意退款',
self::REFUND_REFUSE => '拒绝退款',
self::REFUND_DELIVER => '等待客户退货',
self::REFUND_DELIVERED => '客户退货,等待签收',
self::REFUND_SIGNED => '已签收',
self::REFUND_PROCESS => '退款中',
self::REFUND_COMPLETED => '退款完成',
];
/**
* @var array
*/
protected $dates = [
'refunded_at',
];
public static function boot()
{
parent::boot();
self::creating(function ($model) {
$model->state = self::REFUND_APPLY;
$time = explode(' ', microtime());
$counter = $model->whereDate('created_at', Carbon::today())->count() + 1;
$len = config('mall.refund_no_counter_length');
$prefix = config('refund_no_counter_prefix');
$len = $len < 6 ? 6 : $len;
$len = $len > 16 ? 16 : $len;
$model->refund_no = $prefix . date('YmdHis') .
sprintf('%06d', $time[0] * 1e6) .
sprintf('%0' . $len . 'd', $counter);
});
}
/**
* 获取该模型的路由的自定义键名
* @return string
*/
public function getRouteKeyName(): string
{
return 'refund_no';
}
/**
* Notes: 退款单详情
* @Author: <C.Jason>
* @Date : 2019/11/22 4:25 下午
* @return HasMany
*/
public function items(): HasMany
{
return $this->hasMany(RefundItem::class);
}
/**
* Notes: 退款单物流
* @Author: <C.Jason>
* @Date : 2019/11/22 4:25 下午
* @return HasOne
*/
public function express(): HasOne
{
return $this->hasOne(RefundExpress::class);
}
/***
* Notes: 获取状态
* @Author: 玄尘
* @Date : 2021/5/18 11:50
*/
public function getStatusTextAttribute(): string
{
return self::STATUS_MAP[$this->state] ?? '---';
}
/**
* Notes: 获取退款状态
* @Author: <C.Jason>
* @Date : 2019/11/22 4:25 下午
* @return string
*/
protected function getStateTextAttribute(): string
{
switch ($this->state) {
case self::REFUND_APPLY:
$state = '退款申请中';
break;
case self::REFUND_AGREE:
$state = '同意退款';
break;
case self::REFUND_PROCESS:
$state = '退款中,请等待商家打款';
break;
case self::REFUND_COMPLETED:
$state = '退款完毕';
break;
case self::REFUND_REFUSE:
$state = '拒绝退款';
break;
case self::REFUND_DELIVER:
$state = '您的申请已经通过,请将商品退回给商家';
break;
case self::REFUND_DELIVERED:
$state = '客户退货,等待签收';
break;
case self::REFUND_SIGNED:
$state = '店家已签收,等待打款';
break;
default:
$state = '未知状态';
break;
}
return $state;
}
/**
* Notes : 关联店铺
* @Date : 2021/5/7 1:46 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function shop(): BelongsTo
{
return $this->belongsTo(Shop::class);
}
/**
* Notes: 关联日志
* @Author: 玄尘
* @Date : 2021/5/17 11:38
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function logs(): HasMany
{
return $this->hasMany(RefundLog::class);
}
/**
* Notes : 工作流获取状态
* @Date : 2021/5/8 3:52 下午
* @Author : < Jason.C >
* @return string
*/
public function getCurrentState(): string
{
return $this->state;
}
/**
* Notes : 工作流设置状态
* @Date : 2021/5/8 4:01 下午
* @Author : < Jason.C >
* @param $state
*/
public function setCurrentState($state)
{
$this->state = $state;
$this->save();
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Modules\Mall\Models\Traits\BelongsToRefund;
use Modules\Mall\Models\Traits\HasRegion;
class RefundExpress extends Model
{
use BelongsToRefund,
HasRegion;
protected $table = 'mall_refund_expresses';
protected $dates = [
'deliver_at',
'receive_at',
];
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Modules\Mall\Models\Traits\BelongsToOrder;
use Modules\Mall\Models\Traits\BelongsToRefund;
class RefundItem extends Model
{
use BelongsToOrder,
BelongsToRefund;
const UPDATED_AT = null;
protected $table = 'mall_refund_items';
public $casts = [
'source' => 'json',
];
/**
* Notes: 关联order_item
* @Author: 玄尘
* @Date : 2021/5/19 9:50
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function order_item(): BelongsTo
{
return $this->belongsTo(OrderItem::class);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Modules\Mall\Models\Traits\BelongsToRefund;
class RefundLog extends Model
{
use BelongsToRefund;
const UPDATED_AT = null;
protected $table = 'mall_refund_logs';
/**
* Notes: 操作用户
* @Author: 玄尘
* @Date : 2021/5/17 11:32
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function userable(): MorphTo
{
return $this->morphTo();
}
/**
* Notes: 状态
* @Author: 玄尘
* @Date : 2021/5/18 11:39
* @return string
*/
public function getStateTextAttribute(): string
{
return Refund::STATUS_MAP[$this->state] ?? '---';
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Region extends Model
{
use Cachable;
protected $table = 'mall_regions';
public $timestamps = false;
/**
* Notes: 上级地区
* @Author: <C.Jason>
* @Date : 2019/11/19 3:01 下午
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function parent(): BelongsTo
{
return $this->belongsTo(__CLASS__, 'parent_id');
}
/**
* Notes: 下级地区
* @Author: <C.Jason>
* @Date : 2019/11/19 3:01 下午
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function children(): HasMany
{
return $this->hasMany(__CLASS__, 'parent_id');
}
/**
* Notes : 获取区划层级名称
* @Date : 2021/5/6 1:47 下午
* @Author : < Jason.C >
* @return string
*/
public function getDepthNameAttribute(): string
{
switch ($this->depth) {
case 0:
return '国家级';
case 1:
return '省级';
case 2:
return '市级';
case 3:
return '区县';
default:
return '';
}
}
}

View File

@@ -0,0 +1,187 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\HasCovers;
use App\Traits\OrderByOrderAsc;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\HasRegion;
use Modules\Mall\Models\Traits\ShopActions;
use Modules\User\Models\User;
use Modules\User\Traits\BelongsToUser;
use Overtrue\LaravelVersionable\Versionable;
class Shop extends Model
{
use BelongsToUser,
Cachable,
HasCovers,
HasRegion,
OrderByOrderAsc,
Versionable,
ShopActions,
SoftDeletes;
const STATUS_APPLYING = 0;
const STATUS_NORMAL = 1;
const STATUS_REJECT = 2;
const STATUS_CLOSE = 3;
const STATUS_MAP = [
self::STATUS_APPLYING => '待审核',
self::STATUS_NORMAL => '正常',
self::STATUS_REJECT => '驳回申请',
self::STATUS_CLOSE => '关闭',
];
const LABEL_MAP = [
self::STATUS_APPLYING => 'default',
self::STATUS_NORMAL => 'success',
self::STATUS_REJECT => 'warning',
self::STATUS_CLOSE => 'danger',
];
protected $table = 'mall_shops';
protected $casts = [
'pictures' => 'json',
'configs' => 'json',
];
/**
* 不参与版本记录的字段
* @var array|string[]
*/
protected array $dontVersionable = ['updated_at'];
/**
* Notes : 店铺支持的物流
* @Date : 2021/5/6 5:20 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function expresses(): BelongsToMany
{
return $this->belongsToMany(Express::class, 'mall_shop_express')
->withTimestamps();
}
/**
* Notes : 店铺的商品
* @Date : 2021/5/6 5:32 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function goods(): HasMany
{
return $this->hasMany(Goods::class);
}
/**
* Notes : 分类
* @Date : 2021/5/6 5:32 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function categories(): HasMany
{
return $this->hasMany(Category::class);
}
/**
* Notes : 店铺设置的标签
* @Date : 2021/5/13 10:34 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function tags(): HasMany
{
return $this->hasMany(Tag::class);
}
/**
* Notes : 店铺的品牌
* @Date : 2021/5/13 10:35 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function brands(): HasMany
{
return $this->hasMany(Brand::class);
}
/**
* Notes : 轮播图
* @Date : 2021/5/13 11:34 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function banners(): HasMany
{
return $this->hasMany(Banner::class);
}
/**
* Notes : 订单
* @Date : 2021/5/6 5:33 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function orders(): HasMany
{
return $this->hasMany(Order::class);
}
/**
* Notes : 退款订单
* @Date : 2021/5/7 9:16 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function refunds(): HasMany
{
return $this->hasMany(Refund::class);
}
/**
* Notes : 获取状态文本
* @Date : 2021/5/7 10:57 上午
* @Author : < Jason.C >
* @return string
*/
public function getStatusTextAttribute(): string
{
return self::STATUS_MAP[$this->status] ?? '未知状态';
}
/**
* Notes: 退货理由
* @Author: 玄尘
* @Date : 2021/5/18 15:31
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function reasons(): BelongsToMany
{
return $this->belongsToMany(Reason::class, 'mall_shop_reasons')
->withTimestamps();
}
/**
* Notes : 店铺的员工
* @Date : 2021/7/1 4:25 下午
* @Author : < Jason.C >
*/
public function staffers(): BelongsToMany
{
return $this->belongsToMany(User::class, 'mall_shop_staffers')
->using(ShopStaffer::class)
->withPivot('job_id')
->withTimestamps();
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Modules\Mall\Models;
use Encore\Admin\Traits\DefaultDatetimeFormat;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;
use Modules\Mall\Models\Traits\BelongsToShop;
use Modules\User\Traits\BelongsToUser;
class ShopStaffer extends Pivot
{
use BelongsToShop,
BelongsToUser,
DefaultDatetimeFormat;
protected $table = 'mall_shop_staffers';
/**
* Notes : 职位
* @Date : 2021/7/1 4:38 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function job(): BelongsTo
{
return $this->belongsTo(Job::class);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Modules\Mall\Models\Traits\BelongsToShop;
class Tag extends Model
{
use BelongsToShop,
Cachable;
protected $table = 'mall_tags';
/**
* Notes : 标签下的商品
* @Date : 2021/5/12 10:14 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function goods(): BelongsToMany
{
return $this->belongsToMany(Goods::class, 'mall_goods_tag')->withTimestamps();
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Modules\Mall\Models\Traits;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Modules\Mall\Models\Order;
trait BelongsToOrder
{
/**
* Notes : 隶属订单
* @Date : 2021/3/15 1:29 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function order(): BelongsTo
{
return $this->belongsTo(Order::class);
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Modules\Mall\Models\Traits;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Modules\Mall\Models\Refund;
trait BelongsToRefund
{
/**
* Notes: 所属退款单
* @Author: 玄尘
* @Date : 2021/5/20 13:58
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function refund(): BelongsTo
{
return $this->belongsTo(Refund::class);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Modules\Mall\Models\Traits;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Modules\Mall\Models\Shop;
trait BelongsToShop
{
/**
* Notes : 隶属店铺
* @Date : 2021/5/6 2:49 下午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function shop(): BelongsTo
{
return $this->belongsTo(Shop::class);
}
/**
* Notes : 作用域查询
* @Date : 2021/6/21 8:57 上午
* @Author : < Jason.C >
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Modules\Mall\Models\Shop $shop
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeByShop(Builder $query, Shop $shop): Builder
{
return $query->where('shop_id', $shop->getKey());
}
/**
* Notes : 店铺ID 作用域查询
* @Date : 2021/6/21 9:04 上午
* @Author : < Jason.C >
* @param \Illuminate\Database\Eloquent\Builder $query
* @param int $shopId
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeByShopId(Builder $query, int $shopId): Builder
{
return $query->where('shop_id', $shopId);
}
}

View File

@@ -0,0 +1,206 @@
<?php
namespace Modules\Mall\Models\Traits;
use Modules\Mall\Models\Goods;
use Modules\User\Models\User;
trait GoodsAttribute
{
/**
* Notes: 获取商品库存
*
* @Author: 玄尘
* @Date : 2021/5/14 11:17
* @param int $user_id
* @return int
*/
public function getGoodsStock(int $user_id = 0): int
{
if ($this->goods->type == Goods::TYPE_SINGLE) {
}
return $this->stock ?? 0;
}
/**
* Notes: 扣除库存方法
*
* @Author: 玄尘
* @Date : 2021/5/14 11:12
* @param $stock
* @param $user_id
* @return bool
*/
public function deductStock($stock, $user_id): bool
{
$this->decrement('stock', $stock);
return true;
}
/**
* Notes: 增加库存方法
*
* @Author: 玄尘
* @Date : 2021/5/14 11:12
* @param $stock
*/
public function addStock($stock)
{
$this->increment('stock', $stock);
}
/**
* Notes: 增加销量
*
* @Author: 玄尘
* @Date : 2021/5/14 11:12
* @param $sold
*/
public function addSold($sold)
{
$this->goods()->increment('sales', $sold);
}
/**
* Notes: 减少销量
*
* @Author: 玄尘
* @Date : 2021/5/14 11:12
* @param $sold
*/
public function deductSold($sold)
{
$this->goods()->decrement('sales', $sold);
}
/**
* Notes: 获取卖家ID
*
* @Author: 玄尘
* @Date : 2021/5/14 11:14
* @return int
*/
public function getShopIdAttribute(): int
{
return $this->goods->shop_id ?? 0;
}
/**
* Notes: 获取卖家type
*
* @Author: 玄尘
* @Date : 2021/5/14 11:14
* @return string|null
*/
public function getShopTypeAttribute(): ?string
{
if ($this->goods && $this->goods->shop) {
return get_class($this->goods->shop);
}
return null;
}
/**
* Notes: 获取卖家名称
*
* @Author: 玄尘
* @Date : 2021/5/14 11:14
* @return false|string|null
*/
public function getShopNameAttribute()
{
if ($this->goods && $this->goods->shop) {
return $this->goods->shop->name;
}
return null;
}
/**
* Notes: 重量
*
* @Author: 玄尘
* @Date : 2021/5/14 11:15
* @return int
*/
public function getGoodsWeight(): int
{
return $this->weight ?? 0;
}
/**
* Notes: 返回source
*
* @Author: 玄尘
* @Date : 2021/5/14 11:15
* @return array
*/
public function getSource(): array
{
return [
'goods_sku_id' => $this->id,
'goods_id' => $this->goods_id,
'deduct_stock_type' => $this->goods->deduct_stock_type,
'goods_name' => $this->getGoodsName(),
// 'unit' => $this->getItemValue(),
'cover' => $this->goods->cover_url,
'price' => $this->getItemPrice(),
'stock' => $this->getGoodsStock(),
'weight' => $this->weight,
'is_post_sale' => $this->goods->is_post_sale ?? 0,
'score' => $this->score, // 积分/原石
'assets' => $this->assets, // 资产
];
}
/**
* Notes: 获取商品名称
*
* @Author: 玄尘
* @Date : 2021/5/14 11:19
* @return string
*/
public function getGoodsName(): string
{
return $this->goods->name ?? '--';
}
/**
* Notes: 获取商品规格名称
*
* @Author: 玄尘
* @Date : 2021/5/14 11:16
* @return string
*/
public function getItemValue(): string
{
switch ($this->goods->type) {
case Goods::TYPE_SINGLE:
return '';
case Goods::TYPE_MULTIPLE:
return $this->unit ?? '';
}
}
/**
* Notes: 获取商品单价
*
* @Author: 玄尘
* @Date : 2021/5/14 11:16
* @return mixed
*/
public function getItemPrice()
{
$tags = $this->goods->tags()->pluck('tag_id')->toArray();
//1 为试用产品
if (in_array(1, $tags)) {
return 0;
}
return $this->price;
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace Modules\Mall\Models\Traits;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Modules\Mall\Models\Region;
trait HasRegion
{
/**
* Notes : 省份
*
* @Date : 2021/5/11 9:49 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function province(): BelongsTo
{
return $this->belongsTo(Region::class, 'province_id');
}
/**
* Notes : 市
*
* @Date : 2021/5/11 9:50 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function city(): BelongsTo
{
return $this->belongsTo(Region::class, 'city_id');
}
/**
* Notes : 区
*
* @Date : 2021/5/11 9:50 上午
* @Author : < Jason.C >
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function district(): BelongsTo
{
return $this->belongsTo(Region::class, 'district_id');
}
/**
* Notes : 获取完整地址
*
* @Date : 2021/5/11 9:49 上午
* @Author : < Jason.C >
* @param string $separators 地址的分隔符
* @return string
*/
public function getFullAddress(string $separators = ' '): string
{
return
$this->province->name.$separators.
$this->city->name.$separators.
$this->district->name.$separators.
$this->address;
}
public function getAllAddress()
{
return $this->name.' '.$this->mobile.' '.$this->getFullAddress();
}
}

View File

@@ -0,0 +1,185 @@
<?php
namespace Modules\Mall\Models\Traits;
use App\Notifications\SystemOrderDelivered;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Modules\Mall\Events\OrderCanceled;
use Modules\Mall\Events\OrderCompleted;
use Modules\Mall\Events\OrderDelivered;
use Modules\Mall\Events\OrderPaid;
use Modules\Mall\Events\OrderSigned;
use Modules\Mall\Models\Order;
trait OrderActions
{
/**
* Notes : 订单取消
*
* @Date : 2021/5/17 10:36 上午
* @Author : < Jason.C >
* @throws \Exception
*/
public function cancel(): bool
{
if ($this->canCancel()) {
// 修改状态机
$this->apply('cancel');
event(new OrderCanceled($this));
return true;
} else {
throw new \Exception('订单状态不可取消');
}
}
/**
* 订单支付
*
* @throws \Exception
*/
public function pay(): bool
{
if ($this->can('pay')) {
// 修改状态机
$this->paid_at = Carbon::now();
$this->apply('pay');
event(new OrderPaid($this));
return true;
} else {
throw new \Exception('订单状态不可支付');
}
}
/**
* Notes : 订单发货
*
* @Date : 2021/5/14 16:45
* @Author : Mr.wang
* @param int $expressId 物流公司ID
* @param string $expressNo 物流单号
* @return bool
* @throws \Exception
*/
public function deliver($expressId, $expressNo, $type = 1, $person = ''): bool
{
if ($this->can('deliver')) {
if ($this->refund_items_count == $this->items()->count()) {
throw new \Exception('商品已全部退款/货不能发货');
}
DB::transaction(function () use ($expressId, $expressNo, $type, $person) {
$this->express()->update([
'express_id' => $expressId ?? null,
'express_no' => $expressNo ?? null,
'type' => $type,
'person' => $person,
'deliver_at' => now(),
]);
// 修改状态机
$this->apply('deliver');
event(new OrderDelivered($this));
// if ($this->type == Order::TYPE_SAMPLE) {
// $this->user->notify(new SystemOrderDelivered('发货提醒', $this));
// }
});
return true;
} else {
throw new \Exception('订单状态不可发货');
}
}
/**
* Notes : 订单签收
*
* @Date : 2021/5/14 17:09
* @Author : Mr.wang
* @return bool
* @throws \Exception
*/
public function sign(): bool
{
if ($this->can('sign')) {
DB::transaction(function () {
$this->express()->update([
'receive_at' => now(),
]);
// 修改状态机
$this->apply('sign');
});
event(new OrderSigned($this));
return true;
} else {
throw new \Exception('订单状态不可签收');
}
}
/**
* Notes : 订单完成
*
* @Date : 2021/5/21 2:57 下午
* @Author : < Jason.C >
* @return bool
* @throws \Exception
*/
public function complete(): bool
{
if ($this->can('complete')) {
// 修改状态机
$this->apply('complete');
event(new OrderCompleted($this));
return true;
} else {
throw new \Exception('订单状态不可完成');
}
}
/**
* Notes: 设置退款
*
* @Author: 玄尘
* @Date : 2021/6/9 9:53
*/
public function refund()
{
if ($this->can('refund')) {
// 修改状态机
$this->apply('refund');
return true;
} else {
throw new \Exception('订单状态不可设置退款');
}
}
/**
* Notes: 退款完成
*
* @Author: 玄尘
* @Date : 2021/6/9 12:00
*/
public function completed()
{
if ($this->can('completed')) {
// 修改状态机
$this->apply('completed');
return true;
} else {
throw new \Exception('订单状态不可设置退款完成');
}
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace Modules\Mall\Models\Traits;
use Modules\Mall\Models\Order;
trait OrderCando
{
/**
* Notes: 是否可支付
*
* @Author: <C.Jason>
* @Date : 2019/11/20 3:39 下午
* @return bool
*/
public function canPay(): bool
{
return $this->can('pay');
}
/**
* Notes: 是否可取消
*
* @Author: <C.Jason>
* @Date : 2019/11/20 3:39 下午
* @return bool
*/
public function canCancel(): bool
{
return in_array($this->state, [Order::STATUS_INIT,]);
}
/**
* 可发货
*
* @Author:<C.Jason>
* @Date :2018-10-22T17:12:13+0800
* @return boolean
*/
public function canDeliver(): bool
{
return $this->can('deliver');
}
/**
* 可签收
*
* @Author:<C.Jason>
* @Date :2018-10-22T17:12:43+0800
* @return boolean
*/
public function canSign(): bool
{
return $this->can('sign');
}
/**
* 可完成订单
*
* @Author:<C.Jason>
* @Date :2018-10-25T17:35:12+0800
* @return boolean
*/
public function canComplete(): bool
{
return $this->can('complete');
}
/**
* 可申请退款
*
* @Author:<C.Jason>
* @Date :2018-10-22T17:11:45+0800
* @return boolean
*/
public function canRefund(): bool
{
return $this->can('refund');
}
}

View File

@@ -0,0 +1,138 @@
<?php
namespace Modules\Mall\Models\Traits;
use Illuminate\Database\Eloquent\Builder;
use Modules\Mall\Models\Order;
trait OrderScopes
{
/**
* Notes : 未支付
*
* @Date : 2021/5/17 10:59 上午
* @Author : < Jason.C >
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeUnPay(Builder $query): Builder
{
return $query->where('state', self::STATUS_INIT);
}
/**
* Notes : 已支付,待发货
*
* @Date : 2021/5/17 11:00 上午
* @Author : < Jason.C >
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopePaid(Builder $query): Builder
{
return $query->where('state', self::STATUS_PAID);
}
/**
* Notes : 已发货,代签收
*
* @Date : 2021/5/17 11:03 上午
* @Author : < Jason.C >
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeDelivered(Builder $query): Builder
{
return $query->where('state', self::STATUS_DELIVERED);
}
/**
* Notes : 已签收
*
* @Date : 2021/5/17 11:04 上午
* @Author : < Jason.C >
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeSigned(Builder $query): Builder
{
return $query->where('state', self::STATUS_SIGNED);
}
/**
* Notes : 已完成的订单
*
* @Date : 2021/5/17 11:04 上午
* @Author : < Jason.C >
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeCompleted(Builder $query): Builder
{
return $query->where('state', self::STATUS_COMPLETED);
}
/**
* Notes : 订单列表排除退款部分
*
* @Date : 2021/5/18 9:50
* @Author : Mr.wang
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeCommon(Builder $query): Builder
{
return $query->whereIn('state', [
self::STATUS_INIT,
self::STATUS_CANCEL,
self::STATUS_PAID,
self::STATUS_DELIVERED,
self::STATUS_SIGNED,
self::STATUS_COMPLETED,
]);
}
/**
* Notes: 签收和发货
*
* @Author: 玄尘
* @Date: 2022/8/30 8:33
* @param Builder $query
* @return Builder
*/
public function scopeDeliveredAndSigned(Builder $query): Builder
{
return $query->whereIn('state', [
self::STATUS_DELIVERED,
self::STATUS_SIGNED,
]);
}
/**
* Notes: 积分兑换订单
*
* @Author: 玄尘
* @Date: 2022/9/19 14:40
* @param Builder $query
* @return Builder
*/
public function scopeTypeScore(Builder $query): Builder
{
return $query->where('type', Order::TYPE_SCORE);
}
/**
* Notes: 提货订单
*
* @Author: 玄尘
* @Date: 2022/9/19 14:40
* @param Builder $query
* @return Builder
*/
public function scopeTypeSample(Builder $query): Builder
{
return $query->where('type', Order::TYPE_SAMPLE);
}
}

View File

@@ -0,0 +1,318 @@
<?php
namespace Modules\Mall\Models\Traits;
use Encore\Admin\Facades\Admin;
use Exception;
use Illuminate\Support\Facades\DB;
use Modules\Mall\Events\RefundAgreed;
use Modules\Mall\Events\RefundCompleted;
use Modules\Mall\Events\RefundRefused;
use Modules\Payment\Models\Payment;
trait RefundActions
{
public $operator;
/**
* Notes: 设置操作人
*
* @Author: 玄尘
* @Date : 2021/5/17 16:12
* @param $operator
* @return $this
*/
public function setOperator($operator)
{
$this->operator = $operator;
return $this;
}
/**
* Notes: 设置备注
*
* @Author: 玄尘
* @Date : 2021/5/17 16:12
* @param $remark
* @return $this
*/
public function setRemark($remark)
{
$this->remark = $remark;
return $this;
}
/**
* Notes: 同意退款
*
* @Author: 玄尘
* @Date : 2021/5/17 11:59
* @param $remark
* @return bool
* @throws \Exception
*/
public function agree($remark = null): bool
{
if (! $this->can('agree')) {
throw new Exception("退款单状态不可以同意退款");
}
DB::transaction(function () use ($remark) {
$this->actual_total = $this->refund_total;
$this->save();
$this->apply('agree');
$this->setOrderApply($this->order, 'agree');
if ($this->order->express) {
$this->express()->create();
}
$this->setLogs($remark);
//订单已经进入发货流程,需要客户退货
if ($this->order->express && $this->order->express->deliver_at) {
$this->apply('deliver');
$this->setOrderApply($this->order, 'user_deliver');
} else {
//未发货设置为退款中
$this->apply('process');
$this->setOrderApply($this->order, 'process');
}
event(new RefundAgreed($this));
});
return true;
}
/**
* Notes: 拒绝退款
*
* @Author: 玄尘
* @Date : 2021/5/17 12:01
* @param string|null $remark
* @return bool
* @throws \Exception
*/
public function refuse(string $remark = null): bool
{
if (! $this->can('refuse')) {
throw new Exception("退款单状态不可以拒绝退款");
}
DB::transaction(function () use ($remark) {
$this->apply('refuse');
$this->setOrderApply($this->order, 'refuse');
$this->setLogs($remark);
event(new RefundRefused($this));
});
return true;
}
/**
* Notes: 退货退款中
*
* @Author: 玄尘
* @Date : 2021/5/17 14:29
* @param $company
* @param string $number
* @return bool
* @throws \Exception
*/
public function deliver($company, string $number): bool
{
if ($this->can('delivered')) {
DB::transaction(function () use ($company, $number) {
$this->express()->update([
'company' => $company,
'number' => $number,
'deliver_at' => now(),
]);
// 修改状态机
$this->apply('delivered');
$this->setOrderApply($this->order, 'user_deliverd');
$this->setLogs('客户退货');
});
return true;
} else {
throw new Exception('订单状态不可发货');
}
}
/**
* Notes: 确认收货
*
* @Author: 玄尘
* @Date : 2021/5/17 14:30
* @return bool
* @throws \Exception
*/
public function receive(): bool
{
if (! $this->can('sign')) {
throw new Exception('退款单状态不可以确认收货');
}
$this->express->receive_at = now();
$this->express->save();
$this->apply('sign');
//设置为退款中
$this->apply('process');
$this->setOrderApply($this->order, 'process');
$this->setLogs('店家签收');
return true;
}
/**
* Notes: 标记退款完成
*
* @Author: 玄尘
* @Date : 2021/5/17 14:32
* @return bool
* @throws \Exception
*/
public function complete(): bool
{
if (! $this->can('completed')) {
throw new Exception("订单状态不对,不可设置完成");
}
DB::transaction(function () {
$this->apply('completed');
//设置时间
$this->refunded_at = now();
$this->save();
$this->setLogs('订单标记完成');
event(new RefundCompleted($this));
});
return true;
}
/**
* Notes: 退款
*
* @Author: 玄尘
* @Date : 2021/5/17 14:52
* @throws \Exception
*/
public function returns(): bool
{
try {
$payment = $this->order->payment;
if (! $payment) {
throw new Exception("退款失败,未找到支付信息");
}
//微信支付
if ($payment->driver == Payment::DRIVER_WECHAT) {
$order = [
'out_trade_no' => $payment->trade_id,
'out_refund_no' => $this->refund_no,
'total_fee' => $payment->total * 100,
'refund_fee' => $this->actual_total * 100,
];
$result = app('pay.wechat')->refund($order);
if ($result->result_code != 'SUCCESS') {
throw new Exception("退款失败,".$result->return_msg);
}
$this->setLogs('退款完成');
return true;
} elseif ($payment->driver == Payment::DRIVER_ALIPAY) {//支付宝支付
$order = [
'out_trade_no' => $this->order->order_no,
'refund_amount' => $this->actual_total,
];
$result = app('pay.alipay')->refund($order);
if ($result->code != '10000') {
throw new Exception("退款失败,".$result->msg);
}
return true;
} elseif ($payment->driver == Payment::DRIVER_SCORE) {//水滴支付
$this->user->account->rule('score_buy_refund', $this->actual_total, false, [
'order_no' => $this->order->order_no,
'refund_no' => $this->refund_no,
]);
return true;
} else {
throw new Exception("退款失败,未找到支付路径");
}
} catch (Exception $exception) {
throw new Exception($exception->getMessage());
}
}
/**
* Notes: 记录日志
*
* @Author: 玄尘
* @Date : 2021/5/17 16:03
* @param null $remark
* @param null $title
* @param null $pictures
*/
public function setLogs($remark = null, $title = null, $pictures = null)
{
if (empty($this->operator)) {
$this->operator = $this->user;
}
if (empty($this->operator)) {
$this->operator = Admin::user();
}
$refund = $this->refresh();
$logs = [
'userable_type' => get_class($this->operator),
'userable_id' => $this->operator->id,
'remark' => $remark,
'title' => $title,
'pictures' => $pictures,
'state' => $refund->state,
];
$refund->logs()->create($logs);
}
/**
* Notes: 修改订单状态机
*
* @Author: 玄尘
* @Date : 2021/6/17 9:22
*/
public function setOrderApply($order, $status)
{
//如果都已经退款/货
if ($order->refund_items_count == $order->items()->count()) {
$order->apply($status);
}
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Modules\Mall\Models\Traits;
use Exception;
use Modules\Mall\Models\Express;
use Modules\Mall\Models\Reason;
use Modules\Mall\Models\Shop;
trait ShopActions
{
/**
* Notes : 关闭店铺
* @Date : 2021/5/7 4:58 下午
* @Author : < Jason.C >
* @return bool
* @throws \Exception
*/
public function close(): bool
{
if ($this->status != Shop::STATUS_NORMAL) {
throw new Exception('当前状态不可关闭');
}
$this->status = Shop::STATUS_CLOSE;
return $this->save();
}
/**
* Notes : 开启店铺
* @Date : 2021/5/7 5:02 下午
* @Author : < Jason.C >
* @return bool
* @throws \Exception
*/
public function open(): bool
{
if ($this->status != Shop::STATUS_CLOSE) {
throw new Exception('当前状态不可开启');
}
$this->status = Shop::STATUS_NORMAL;
return $this->save();
}
/**
* Notes : 通过申请
* @Date : 2021/5/7 5:03 下午
* @Author : < Jason.C >
* @return bool
* @throws \Exception
*/
public function pass(): bool
{
if ($this->status != Shop::STATUS_APPLYING) {
throw new Exception('当前状态不可审核' . $this->status);
}
// 店铺审核通过后,增加物流的关联
$expressIds = Express::where('status', 1)->pluck('id');
$this->expresses()->attach($expressIds);
$reasonIds = Reason::where('status', 1)->pluck('id');
$this->reasons()->attach($reasonIds);
$this->status = Shop::STATUS_CLOSE;
return $this->save();
}
/**
* Notes : 驳回申请
* @Date : 2021/5/7 5:03 下午
* @Author : < Jason.C >
* @param string $reason
* @return bool
* @throws \Exception
*/
public function reject(string $reason): bool
{
if ($this->status != Shop::STATUS_APPLYING) {
throw new Exception('当前状态不可驳回');
}
$this->status = Shop::STATUS_REJECT;
$this->reject_reason = $reason;
return $this->save();
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Modules\Mall\Models;
use App\Models\Model;
use App\Traits\HasCovers;
use App\Traits\HasStatus;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
class Video extends Model
{
use HasStatus, HasCovers, Cachable;
protected $table = 'mall_videos';
public function getPathUrlAttribute(): string
{
return $this->parseImageUrl($this->path);
}
}