Quote.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. <?php
  2. namespace app\admin\controller\qingdongams\customer;
  3. use addons\qingdongams\model\Customer;
  4. use addons\qingdongams\model\ExamineRecord;
  5. use addons\qingdongams\model\Flow;
  6. use addons\qingdongams\model\Message;
  7. use addons\qingdongams\model\Staff;
  8. use app\admin\controller\qingdongams\Base;
  9. use addons\qingdongams\model\Quote as QuoteModel;
  10. use addons\qingdongams\model\QuoteFile;
  11. use addons\qingdongams\model\QuoteOther;
  12. use addons\qingdongams\model\QuoteProduct;
  13. use PhpOffice\PhpWord\TemplateProcessor;
  14. use think\Db;
  15. use think\Exception;
  16. /**
  17. * 报价单管理
  18. * @icon fa fa-user
  19. */
  20. class Quote extends Base
  21. {
  22. protected $relationSearch = true;
  23. protected $searchFields = 'id,number';
  24. /**
  25. * @var \addons\qingdongams\model\Quote
  26. */
  27. protected $model = null;
  28. public function _initialize()
  29. {
  30. parent::_initialize();
  31. $this->model = new QuoteModel;
  32. }
  33. /**
  34. * 查看
  35. */
  36. public function index()
  37. {
  38. //设置过滤方法
  39. $this->request->filter(['strip_tags', 'trim']);
  40. if ($this->request->isAjax()) {
  41. //如果发送的来源是Selectpage,则转发到Selectpage
  42. if ($this->request->request('keyField')) {
  43. return $this->selectpage();
  44. }
  45. list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  46. $createtime = input('createtime', '');
  47. list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  48. $wheres = [];
  49. if ($createtime && $createtime != 'null ') {
  50. $start = date("Y-m-d H:i:s", mktime(0, 0, 0, date("m"), 1, date("Y")));
  51. $end = date("Y-m-d H:i:s", mktime(23, 59, 59, date("m"), date("t"), date("Y")));
  52. $wheres['createtime'] = array('between', array(strtotime($start), strtotime($end)));
  53. }
  54. $whereFlow = function ($query) {
  55. $query->where('create_staff_id|owner_staff_id', 'in', Staff::getMyStaffIds())
  56. ->whereOr('', 'exp', "FIND_IN_SET({$this->_staff->id},show_staff_id)");
  57. };
  58. $list = $this->model->where($where)->where($wheres)->where($whereFlow)->with(['ownerStaff', 'customer', 'contacts'])->order($sort, $order)->paginate($limit);
  59. $result = array("total" => $list->total(), "rows" => $list->items());
  60. return json($result);
  61. }
  62. return $this->view->fetch();
  63. }
  64. /**
  65. * 添加报价单
  66. */
  67. public function add()
  68. {
  69. if ($this->request->isPost()) {
  70. //移除HTML标签
  71. $this->request->filter('trim');
  72. $params = $this->request->post('row/a');
  73. if (!isset($params['product']) || !$params['product'] || $params['product'] == '[]') {
  74. $this->error('请选择产品');
  75. }
  76. // 表单验证
  77. if (($result = $this->validate($params, 'addons\qingdongams\validate\Quote.create')) !== true) {
  78. $this->error($result);
  79. }
  80. if(isset($params['flow_staff_ids']) && $params['is_check']==1){
  81. if(!$params['flow_staff_ids']){
  82. $this->error('请选择审批人');
  83. }
  84. }
  85. $params['product'] = json_decode($params['product'], true);
  86. foreach ($params['product'] as $v) {
  87. if (empty($v['product_id'])) {
  88. $this->error('产品名称不能为空');
  89. }
  90. if (empty($v['price'])) {
  91. $this->error('产品单价不能为空');
  92. }
  93. if (empty($v['number'])) {
  94. $this->error('产品数量不能为空');
  95. }
  96. }
  97. try {
  98. $result = QuoteModel::createQuote($params);
  99. $customerModel = new Customer();
  100. $customerInfo = $customerModel->where(['id' => $params['customer_id']])->find();
  101. if (!in_array($customerInfo['follow'], ['准备购买', '准备付款', '已经购买'])) {
  102. $customerModel->where(['id' => $params['customer_id']])->update(['follow' => '准备购买']);
  103. }
  104. Db::commit();
  105. } catch (Exception $e) {
  106. Db::rollback();
  107. $this->error($e->getMessage());
  108. }
  109. if ($result) {
  110. $this->success('新增报价单成功');
  111. }
  112. $this->error('新建报价单失败');
  113. }
  114. $clause = "· 交货期:合同生效后,5个、10个、15个、25个、30工作日内发货。<br>
  115. · 交货地点:贵司工厂(仅限大陆工厂)/客户提供指定安装地点<br>
  116. · 保修期:12个月或24个月<br>
  117. · 有效期:30天、60天、90天。<br>
  118. · 付款方式:全款发货/五五/三六一。<br>
  119. · 含税方式:不含税/含13%增值税。";
  120. $flow = Flow::getsteplist(Flow::QUOTE_STATUS);
  121. if (empty($flow)) {
  122. $this->error('无可用审批流,请联系管理员');
  123. }
  124. $this->assign('flow', $flow);
  125. $customer_id = input('customer_id');
  126. $this->assign('customer_id', $customer_id);
  127. $this->view->assign('clause', $clause);
  128. $this->view->assign('number', getItemNumber('quote'));
  129. $this->view->assign('customer', Customer::getList());
  130. return $this->view->fetch();
  131. }
  132. /**
  133. * 修改报价单
  134. */
  135. public function edit($ids = null)
  136. {
  137. $map['id'] = $ids;
  138. if ($this->request->isPost()) {
  139. //移除HTML标签
  140. $this->request->filter('trim');
  141. $params = $this->request->post('row/a');
  142. $row = QuoteModel::where(['id' => $ids])->find();
  143. if (empty($row)) {
  144. $this->error('修改报价单信息不存在');
  145. }
  146. if (!isset($params['product']) || !$params['product'] || $params['product'] == '[]') {
  147. $this->error('请选择产品');
  148. }
  149. $params['product'] = json_decode($params['product'], true);
  150. foreach ($params['product'] as $v) {
  151. if (empty($v['product_id'])) {
  152. $this->error('产品名称不能为空');
  153. }
  154. if (empty($v['price'])) {
  155. $this->error('产品单价不能为空');
  156. }
  157. if (empty($v['number'])) {
  158. $this->error('产品数量不能为空');
  159. }
  160. }
  161. // 表单验证
  162. if (($result = $this->validate($params, 'addons\qingdongams\validate\Quote.create')) !== true) {
  163. $this->error($result);
  164. }
  165. Db::startTrans();
  166. try {
  167. $params['id'] = $ids;
  168. $params['status'] = 0;
  169. QuoteModel::updateQuote($params);
  170. Db::commit();
  171. } catch (Exception $e) {
  172. Db::rollback();
  173. $this->error($e->getMessage());
  174. }
  175. $this->success('修改报价单信息成功');
  176. }
  177. $flow = Flow::getsteplist(Flow::QUOTE_STATUS);
  178. if (empty($flow)) {
  179. $this->error('无可用审批流,请联系管理员');
  180. }
  181. $this->assign('flow', $flow);
  182. $row = $this->model->with(['product', 'customer', 'contacts'])->where($map)->find();
  183. $row = $row->toArray();
  184. $row = QuoteOther::getOther($row);
  185. $this->view->assign("row", $row);
  186. $this->view->assign('customer', Customer::getList());
  187. return $this->view->fetch();
  188. }
  189. /**
  190. * 报价单详情
  191. */
  192. public function detail($ids = null)
  193. {
  194. $row = $this->model->with(['createStaff', 'ownerStaff', 'customer', 'contacts', 'orderStaff'])->where([
  195. 'id' => $ids,
  196. ])->find();
  197. $row = $row->toArray();
  198. $row = QuoteOther::getOther($row);
  199. if ($row['check_status'] == 0 || $row['check_status'] == 1) {
  200. $row['is_examine'] = ExamineRecord::isExaminse(ExamineRecord::QUOTE_TYPE, $ids);
  201. } else {
  202. $row['is_examine'] = 0;
  203. }
  204. Message::setRead(Message::QUOTE_TYPE, $ids, $this->_staff->id);
  205. $product = QuoteProduct::where(['quote_id' => $ids])->with(['product'])->select();
  206. $this->assign('flow', Flow::getstepdetail(Flow::QUOTE_STATUS, $ids));
  207. $this->assign('examine_record', ExamineRecord::getList(ExamineRecord::QUOTE_TYPE, $ids));
  208. $this->assign('product', $product);
  209. $this->assign('row', $row);
  210. $this->assign('ids', $ids);
  211. $this->assignconfig("idinfo", ['id' => $ids]);
  212. return $this->view->fetch();
  213. }
  214. /**
  215. * 获取附件记录
  216. */
  217. public function get_file($ids = null)
  218. {
  219. list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  220. $list = \addons\qingdongams\model\QuoteFile::where(['quote_id' => $ids])->with(['file', 'auth'])->field('file_id,createtime,create_id')->paginate($limit);
  221. $result = array("total" => $list->total(), "rows" => $list->items());
  222. return json($result);
  223. }
  224. /**
  225. * 添加附件记录
  226. */
  227. public function img($ids = null)
  228. {
  229. $map['id'] = $ids;
  230. if ($this->request->isPost()) {
  231. $params = $this->request->post('row/a');
  232. Db::startTrans();
  233. try {
  234. QuoteFile::addFiles($params['fild_ids'], $ids, $this->_staff->id);
  235. Db::commit();
  236. } catch (Exception $e) {
  237. Db::rollback();
  238. $this->error($e->getMessage());
  239. }
  240. $this->success('成功');
  241. }
  242. $this->view->assign("id", $ids);
  243. return $this->view->fetch();
  244. }
  245. /**
  246. * 删除文件
  247. */
  248. public function del_file($ids = "")
  249. {
  250. if (!$this->request->isPost()) {
  251. $this->error(__("Invalid parameters"));
  252. }
  253. $map['file_id'] = $ids;
  254. $result = QuoteFile::where($map)->delete();
  255. if (!$result) {
  256. $this->error('删除失败');
  257. }
  258. $this->success('删除成功');
  259. }
  260. /**
  261. * 作废报价单
  262. */
  263. public function tovoid_quote()
  264. {
  265. $id = input('id');
  266. $row = QuoteModel::where(['id' => $id])->find();
  267. if (empty($row)) {
  268. $this->error('报价单信息不存在');
  269. }
  270. try {
  271. $result = QuoteModel::where(['id' => $id])->update(['status' => 9, 'check_status' => 9]);
  272. ExamineRecord::cancelExaminse(ExamineRecord::QUOTE_TYPE, $id);
  273. } catch (Exception $e) {
  274. $this->error($e->getMessage());
  275. }
  276. if ($result) {
  277. $this->success('作废报价单成功');
  278. }
  279. $this->error('作废失败');
  280. }
  281. /**
  282. * 下载报价单
  283. */
  284. public function download_quote($id = null)
  285. {
  286. $quote = QuoteModel::withTrashed()->where(['id' => $id])
  287. ->with(['customer', 'contacts', 'orderStaff'])->find();
  288. if (empty($quote)) {
  289. $this->error('报价单不存在');
  290. }
  291. $quote = $quote->toArray();
  292. $quoteProduct = QuoteProduct::where(['quote_id' => $id])->with(['product'])->select();
  293. $product_type = json_decode($quote['product_type'], true);
  294. $product_type_name = [];
  295. foreach ($product_type as $t) {
  296. $product_type_name[] = $t['name'] ?? '';
  297. }
  298. $product_type_name = implode(',', $product_type_name);
  299. $tmp = new TemplateProcessor('assets/addons/qingdongams/phpword/baojia1.docx');
  300. \PhpOffice\PhpWord\Settings::setCompatibility(true);
  301. \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
  302. $tmp->setValue('product_type', $product_type_name);//替换变量name
  303. //对齐变量
  304. $name = $quote['customer']['name'] ?? '';
  305. $name = $name . @str_repeat(' ', 13 - mb_strlen($name));
  306. $address = $quote['customer']['address'] ?? '';
  307. $address = $address . @str_repeat(' ', 13 - mb_strlen($address));
  308. $contacts = $quote['contacts']['name'] ?? '';
  309. $contacts = $contacts . @str_repeat(' ', 13 - mb_strlen($contacts));
  310. $mobile = $quote['contacts']['mobile'] ?? '';
  311. $mobile = $mobile . @str_repeat(' ', 13 - ceil(mb_strlen($mobile) / 2));
  312. $order_contacts = $quote['order_staff']['name'] ?? '';
  313. $order_mobile = $quote['order_staff']['mobile'] ?? '';
  314. $tmp->setValue('name', $name);//替换变量name
  315. $tmp->setValue('address', $address);//替换变量address
  316. $tmp->setValue('contacts', $contacts);//替换变量contacts
  317. $tmp->setValue('mobile', $mobile);//替换变量mobile
  318. $tmp->setValue('order_contacts', $order_contacts);
  319. $tmp->setValue('order_mobile', $order_mobile);
  320. $tmp->setValue('price', $quote['quote_amount']);
  321. $tmp->setValue('price_big', convertAmountToCn($quote['quote_amount']));//替换变量mobile
  322. $rows = count($quoteProduct);//总行数
  323. $tmp->cloneRow('num', $rows);//复制行
  324. $content = '';
  325. for ($i = 0; $i < $rows; $i++) {
  326. $tmp->setValue("num#" . ($i + 1), $i + 1);//序号
  327. $tmp->setValue("one#" . ($i + 1), $quoteProduct[$i]['name'] ?? '');//名称
  328. $tmp->setValue("two#" . ($i + 1), $quoteProduct[$i]['product_type']['name'] ?? '');//规格/说明
  329. $tmp->setValue("three#" . ($i + 1), $quoteProduct[$i]['config_desc'] ?? '');//配置说明
  330. $tmp->setValue("four#" . ($i + 1), $quoteProduct[$i]['number'] ?? '');//数量
  331. $tmp->setValue("five#" . ($i + 1), $quoteProduct[$i]['unit'] ?? '');//单位
  332. $tmp->setValue("sex#" . ($i + 1), $quoteProduct[$i]['unit_price'] ?? '');//单价
  333. $tmp->setValue("eight#" . ($i + 1), $quoteProduct[$i]['price'] ?? '');//总价
  334. $tmp->setValue("remarks#" . ($i + 1), $quoteProduct[$i]['remarks'] ?? '');//备注
  335. $content .= "<br>" . $quoteProduct[$i]['description'] ?? '';
  336. }
  337. //start 配置
  338. $configs = [];
  339. foreach ($quoteProduct as $v) {
  340. if ($v['config']) {
  341. $pconfig = [];
  342. foreach ($v['config'] as $vrc) {
  343. $vrc['num'] = $vrc['num'] ?? 0 * $v['number'] ?? 0;
  344. $pconfig[] = $vrc;
  345. }
  346. $configs = array_merge($configs, $pconfig);
  347. }
  348. }
  349. $tmp->cloneRow('i', count($configs));//复制行
  350. $block = [];
  351. foreach ($configs as $k => $ves) {
  352. $block['i#' . ($k + 1)] = $k + 1;
  353. $block['cname#' . ($k + 1)] = $ves['name'];
  354. $block['cnum#' . ($k + 1)] = $ves['num'];
  355. $block['cremark#' . ($k + 1)] = $ves['remark'];
  356. }
  357. $tmp->cloneBlock('config', 1, true, false, [$block]);
  358. //end 配置
  359. //start 特约条款
  360. $clause = strip_tags(html_entity_decode($quote['clause']));
  361. $clause = preg_replace("/(\s|\&nbsp\;| |\xc2\xa0)/", " ", strip_tags($clause)); //去除空格和换行
  362. $clauseList = explode('·', $clause);
  363. $replacements = [];
  364. foreach ($clauseList as $v) {
  365. if ($v) {
  366. $replacements[] = ['clause' => $v];
  367. }
  368. }
  369. $tmp->cloneBlock('clauseBlock', 0, true, false, $replacements);
  370. //end 特约条款
  371. $showNames = [];
  372. foreach ($quoteProduct as $v) {
  373. $showNames[] = $v['name'];
  374. }
  375. $products = \addons\qingdongams\model\Product::where([])->order('id asc')->column('name');
  376. foreach ($products as $v) {
  377. if (in_array($v, $showNames)) {
  378. //显示
  379. $tmp->cloneBlock($v);
  380. } else {
  381. $tmp->cloneBlock($v, 0);
  382. }
  383. }
  384. $filename = $quote['customer']['name'] . date('YmdHis') . '.docx';
  385. $fileurl = './docx/' . date('Ymd') . '/';
  386. if (!file_exists('./docx/')) {
  387. mkdir('./docx/');
  388. }
  389. if (!file_exists($fileurl)) {
  390. mkdir($fileurl);
  391. }
  392. $tmp->saveAs($fileurl . $filename);//另存为
  393. $model = new \addons\qingdongams\model\File();
  394. $data = [
  395. 'types' => 'file',
  396. 'name' => $filename,
  397. 'save_name' => $fileurl . $filename,
  398. 'size' => filesize($fileurl . $filename),
  399. 'file_path' => trim($fileurl, '.') . $filename,
  400. ];
  401. $model->save($data);
  402. $lastid = $model->getLastInsID();
  403. $file = cdnurl($model::getUrl($lastid), true);
  404. $data = ['file' => $file, 'id' => $lastid, 'filename' => $filename];
  405. $this->success('成功', '', $data);;
  406. }
  407. }