* +---------------------------------------------------------------------- */ namespace App\Http\Dao\Client; use App\Constants\CustomEnum\CustomerEnum; use App\Http\Dao\BaseDao; use App\Http\Model\BaseModel; use App\Http\Model\Client\ClientBill; use App\Http\Model\Client\Contract; use App\Http\Model\Client\Customer; use App\Http\Model\Config\FormCate; use App\Http\Model\Config\FormData; use App\Http\Service\Client\ClientBillService; use App\Http\Service\Client\ClientContractSubscribeService; use App\Http\Service\Client\ClientRemindService; use App\Http\Service\Client\Custom\CommonService; use App\Http\Service\Client\CustomerService; use App\Http\Service\Config\DictDataService; use crmeb\traits\dao\ListSearchTrait; use crmeb\traits\dao\TogetherSearchTrait; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Illuminate\Support\HigherOrderWhenProxy; use Illuminate\Support\Str; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; class ContractDao extends BaseDao { use TogetherSearchTrait; use CommonService; use ListSearchTrait; protected string $joinTable; protected $otherSearch = [ 'statistics_type', 'types', 'scope_frame', 'before_salesman', 'customer_repeat_check', 'subscribe_uid', 'payment_time', 'contract_customer', ]; /** * 设置模型. * @return BaseModel * @throws BindingResolutionException */ public function getModel(bool $need = true) { $model = parent::getModel(); $tableName = 'contract_' . $this->entId; $this->createTableIfNotExists($tableName); $model = $model->setTable($tableName); if ($need && $this->entId && Schema::hasColumn($tableName, 'entid')) { $model = $model->where($tableName . '.entid', $this->entId); } return $model; } /** * 创建表. * @return void */ public function createTableIfNotExists(string $tableName) { if (!Schema::hasTable($tableName)) { Schema::create($tableName, function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedInteger('entid')->default($this->entId)->index()->comment('企业ID'); $table->integer('uid')->default(0)->comment('业务员ID'); $table->integer('eid')->default(0)->comment('客户ID'); $table->integer('creator_uid')->default(0)->comment('创建人ID'); $table->string('contract_name')->default('')->comment('合同名称'); $table->string('contract_no')->default('')->comment('合同编号'); $table->decimal('contract_price', 10)->default(0)->comment('合同金额(元)'); $table->decimal('received', 10)->default(0)->comment('回款金额'); $table->decimal('surplus', 10)->default(0)->comment('尾款金额'); $table->string('contract_followed')->default('1')->comment('是否关注'); $table->string('contract_status')->default('')->comment('合同状态'); $table->tinyInteger('renew')->default(0)->comment('是否有续费:0、否;1、是;'); $table->date('start_date')->nullable()->comment('开始时间'); $table->date('end_date')->nullable()->comment('结束时间'); $table->string('signing_status')->default('')->comment('签约状态'); $table->string('b3733f36')->default('')->comment('备注'); $table->string('contract_category')->default('""')->comment('合同分类'); $table->string('contract_cate')->default('""')->comment('合同分类copy'); $table->tinyInteger('is_abnormal')->default(0)->comment('是否异常:1、是;0、否;'); $table->timestamps(); $table->softDeletes(); }); } } /** * @return BaseModel * @throws BindingResolutionException */ public function clientContractJoinModel() { $model = $this->getModel(false); $joinModel = app()->get(Customer::class); $joinTable = $this->joinTable = $joinModel->getTable(); $table = $this->table = $model->getTable(); return $model->join($joinTable, $table . '.eid', '=', $joinTable . '.id'); } /** * 获取合同条数. * @throws BindingResolutionException */ public function getClientContractCount(array $where = []): int { return $this->clientContractJoinModel()->where($where)->count(); } /** * 获取合同列表. * @throws BindingResolutionException */ public function getClientContractList(array $where = [], int $page = 0, int $limit = 0): array { $model = $this->clientContractJoinModel(); $table = $this->table; $joinTable = $this->joinTable; return $model->where($where) ->whereNotNull($table . '.end_date') ->groupBy($table . '.id') ->select([ $table . '.contract_name as title', $table . '.contract_price as price', $table . '.start_date', $table . '.end_date', $table . '.uid', $table . '.id', $joinTable . '.customer_name as name', ]) ->with([ 'card' => fn($qq) => $qq->where('user_enterprise.entid', $where['entid']), ]) ->when($page && $limit, fn($q) => $q->forPage($page, $limit)) ->get()->toArray(); } /** * 合同类型分析. * @throws BindingResolutionException * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function getRankByCategory(string $time, array $userIds, array $categoryId, array $types = [0, 1]): array { $prefix = Config::get('database.connections.mysql.prefix'); $model = $this->getModel(false); $table = $model->getTable(); $joinModel = app()->get(ClientBill::class); $joinTable = $joinModel->getTable(); $preTable = $prefix . $table; $preJoinTable = $prefix . $joinTable; return $model->join($joinTable, function ($join) use ($joinTable, $table, $time, $types) { $join->on($joinTable . '.cid', '=', $table . '.id')->whereIn($joinTable . '.types', $types) ->where($joinTable . '.status', 1)->where($joinTable . '.entid', 1) ->when($time, function ($query) use ($time, $joinTable) { $query->whereBetween($joinTable . '.date', explode('-', $time)); }); })->when($categoryId, function ($query) use ($table, $categoryId) { is_array($categoryId) ? $query->whereIn($table . '.contract_category', $categoryId) : $query->where($table . '.contract_category', $categoryId); })->whereIn($joinTable . '.uid', $userIds)->whereIn($joinTable . '.uid', $userIds) ->selectRaw("`{$preTable}`.`contract_category`, sum(`{$preJoinTable}`.`num`) as `price`")->first()->toArray(); } /** * 插入数据. * @throws BindingResolutionException */ public function insert(array $data): bool { return $this->getModel(false)->insert($data); } /** * 搜索. * @param mixed $where * @return BaseModel|HigherOrderWhenProxy * @throws \ReflectionException * @throws BindingResolutionException */ public function search($where, ?bool $authWhere = null) { $title = $where['title'] ?? ''; $renew = $where['renew'] ?? ''; $ids = $where['ids'] ?? []; if (isset($where['title'])) { unset($where['title']); } if (isset($where['type'])) { unset($where['type']); } if ($renew == 3) { unset($where['renew']); if (isset($where['ids'])) { unset($where['ids']); } } return parent::search($where, $authWhere) ->when($renew == 3, function ($query) use ($ids) { $query->where(function ($query) use ($ids) { $query->where('renew', 0)->orWhere(function ($query) use ($ids) { $query->where('renew', 1)->whereIn('id', $ids); }); }); })->where(function ($query) use ($title) { $query->when($title, function ($query) use ($title) { $query->orWhere('title', 'like', '%' . $title . '%') ->orWhere('contract_no', 'like', '%' . $title . '%') ->orWhere(function ($query) use ($title) { $query->whereIn('eid', function ($query) use ($title) { $query->from('client_list')->select(['id'])->where('name', 'like', '%' . $title . '%'); }); }); }); }); } /** * 合同类型数量. * @throws BindingResolutionException * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function getCountByCategory(string $time, array $userIds, array|int $categoryId = 0): int { $model = $this->getModel(false); $table = $model->getTable(); $preTable = Config::get('database.connections.mysql.prefix') . $table; $joinTable = app()->get(ClientBill::class)->getTable(); return $model->join($joinTable, function ($join) use ($joinTable, $table, $time) { $join->on($joinTable . '.cid', '=', $table . '.id') ->where($joinTable . '.entid', 1)->where($joinTable . '.status', 1)->where($joinTable . '.types', 0) ->when($time, function ($query) use ($time, $joinTable) { $query->whereBetween($joinTable . '.date', explode('-', $time)); }); })->whereIn($joinTable . '.uid', $userIds)->when($categoryId, function ($query) use ($table, $categoryId) { is_array($categoryId) ? $query->whereIn($table . '.contract_category', $categoryId) : $query->where($table . '.contract_category', $categoryId); })->selectRaw("count(DISTINCT `{$preTable}`.`id`) as `count`")->first()?->count ?? 0; } /** * 列表筛选数据. * @param mixed $where * @param mixed $page * @param mixed $limit * @param mixed $with * @throws BindingResolutionException */ public function listSearch($where, $page = 0, $limit = 0, $with = []) { $dao = $this->getModel(false); $where = $this->getWhere($where, CustomerEnum::CONTRACT); foreach ($where as $field => $value) { if ($value === '') { continue; } if (in_array($field, $this->otherSearch)) { switch ($field) { case 'statistics_type': switch ($value) { case 'concern': $cids = app()->get(ClientContractSubscribeService::class)->column(['uid' => $where['subscribe_uid'], 'subscribe_status' => 1], 'cid'); $dao = $dao->whereIn('id', $cids); break; case 'not_signed': $dao = $dao->where('signing_status', 0); break; case 'signed': $dao = $dao->where('signing_status', 1); break; case 'void_signed': $dao = $dao->where('signing_status', 2); break; case 'expired': $dao = $dao->where('signing_status', '<', 2)->whereDate('end_date', '<', now()->toDateString())->where('is_abnormal', 0)->whereNotNull('end_date'); break; case 'urgent_renewal': $cids = app()->get(ClientRemindService::class)->getUrgentRenewalCid(); $dao = $dao->whereIn('id', $cids)->where('signing_status', '<', 2); break; case 'cost_expired': $cids = app()->get(ClientRemindService::class)->getUrgentRenewalCid(true); $dao = $dao->whereIn('id', $cids)->where('signing_status', '<', 2); break; } break; case 'payment_time': $cids = app()->get(ClientBillService::class)->column(['status' => 1, 'types' => -1, 'date' => $value['value']], 'cid'); $dao = $dao->whereIn('id', $cids)->where('signing_status', '<', 2); break; case 'scope_frame': break; case 'contract_customer': $ids = app()->get(CustomerService::class)->column(['name_like' => $value], 'id'); $dao = $dao->whereIn('eid', $ids); break; } unset($where[$field]); } else if ($field == 'contract_category') { $value['value'] && $dao = $dao->whereIn('contract_category', $value['value']); } else if (is_array($value)) { if (isset($value['input_type'])) { $dao = match ($value['input_type']) { 'select', 'checked', 'radio' => $this->getSelectSearch($dao, $field, $value['value']), 'input' => $this->getInputSearch($dao, $field, $value['value']), 'date' => $this->getDateSearch($dao, $field, $value['value']), 'personnel' => $this->getPersonnelSearch($dao, $field, $value['value']), default => $dao->where($field, $value['value']), }; } else { $dao = $dao->whereIn($field, $value); } } else { $dao = $dao->where($field, $value); } } return $dao->when($page && $limit, function ($query) use ($page, $limit) { $query->forPage($page, $limit); })->when($sort = sort_mode('id'), function ($query) use ($sort) { if (is_array($sort)) { foreach ($sort as $k => $v) { if (is_numeric($k)) { $query->orderByDesc($v); } else { $query->orderBy($k, $v); } } } else { $query->orderByDesc($sort); } })->with($with); } /** * 业务员查询. * @param mixed $dao * @param mixed $value * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchSalesman($dao, $value) { return $dao->whereIn('uid', $value); } /** * 客户创建人查询. * @param mixed $dao * @param mixed $value * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchCreator($dao, $value) { return $dao->whereIn('creator_uid', $value); } /** * 合同客户查询. * @param mixed $dao * @param mixed $value * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchContractCustomer($dao, $value) { $ids = app()->get(CustomerService::class)->column(['name_like' => $value], 'id'); return $dao->whereIn('eid', $ids); } protected function setModel(): string { return Contract::class; } private function getInputSearch($dao, $field, $value) { if (method_exists($this, 'search' . Str::studly($field))) { return $this->{'search' . Str::studly($field)}($dao, $value); } return $dao->where($field, 'like', "%{$value}%"); } private function getSelectSearch($dao, $field, $value) { if (method_exists($this, 'search' . Str::studly($field))) { return $this->{'search' . Str::studly($field)}($dao, $value); } return is_array($value) ? $dao->whereIn($field, $value) : $dao->where($field, $value); } private function getPersonnelSearch($dao, $field, $value) { if (method_exists($this, 'search' . Str::studly($field))) { return $this->{'search' . Str::studly($field)}($dao, $value); } return $dao->whereIn($field, $value); } /** * 付款单号查询. * @param mixed $dao * @param mixed $value * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ private function searchBillNo($dao, $value): mixed { $ids = app()->get(ClientBillService::class)->column(['bill_no_like' => $value], 'cid'); return $dao->whereIn('id', $ids); } /** * 合同分类查询. * @param mixed $dao * @param mixed $value */ private function searchContractCategory($dao, $value): mixed { $cate = app()->get(DictDataService::class)->getCompleteData('contract_type', $value); return $dao->where('contract_category', json_encode($cate)); } }