diff --git a/app/Admin/Actions/Store/RowDeskWxCode.php b/app/Admin/Actions/Store/RowDeskWxCode.php new file mode 100644 index 00000000..269f094e --- /dev/null +++ b/app/Admin/Actions/Store/RowDeskWxCode.php @@ -0,0 +1,27 @@ +getKey()); + $result = $model->generateWxCode(); + if ($result !== true) { + return $this->response()->error(data_get($result, 'errmsg'))->refresh(); + } + return $this->response()->success('操作成功')->refresh(); + } + + public function confirm() + { + return ['是否确定?']; + } +} + diff --git a/app/Admin/Controllers/Store/DeskController.php b/app/Admin/Controllers/Store/DeskController.php new file mode 100644 index 00000000..e8916f22 --- /dev/null +++ b/app/Admin/Controllers/Store/DeskController.php @@ -0,0 +1,90 @@ +model()->orderBy('created_at', 'desc'); + + $grid->column('id'); + $grid->column('store_id')->display(fn() => data_get($this->store, 'title')); + $grid->column('name'); + // $grid->column('status')->switch(); + $grid->column('wxcode')->image('', 100, 100); + $grid->column('remarks')->editable(); + + $user = Admin::user(); + + $grid->showViewButton($user->can('dcat.admin.store.desk.show')); + $grid->showCreateButton($user->can('dcat.admin.store.desk.create')); + $grid->showEditButton($user->can('dcat.admin.store.desk.edit')); + $grid->showDeleteButton($user->can('dcat.admin.store.desk.destroy')); + + $grid->filter(function (Grid\Filter $filter) { + $filter->panel(); + $filter->equal('store_id')->select('api/store')->width(3); + $filter->like('name')->width(3); + }); + + $grid->actions(new \App\Admin\Actions\Store\RowDeskWxCode()); + }); + } + + protected function form() + { + return Form::make(new Desk(), function (Form $form) { + $form->select('store_id')->options(Store::pluck('title', 'id'))->required(); + $form->text('name')->required(); + // $form->switch('status')->default(1); + $form->text('remarks'); + + $form->embeds('extra', function (Form\EmbeddedForm $form) { + $form->select('category_id')->options(ProductCategory::selectOptions()); + }); + + $form->disableCreatingCheck(); + $form->disableEditingCheck(); + $form->disableDeleteButton(); + $form->disableResetButton(); + + $form->saved(function (Form $form, $result) { + // 新增桌号, 生成小程序码 + if ($form->isCreating()) { + + } + }); + }); + } + + protected function detail($id) + { + return Show::make($id, Desk::with(['store']), function (Show $show) { + $show->field('id'); + $show->field('store_id')->as(fn() => data_get($this->store, 'name')); + $show->field('name'); + // $show->field('status')->bool(); + $show->field('wxcode'); + $show->field('remarks'); + + $model = $show->model(); + $category_id = data_get($model->extra, 'category_id'); + if ($category_id) { + $category = ProductCategory::find($category_id); + $show->field('category_id')->as(fn() => $category ? $category->name : $category_id); + } + + $show->disableEditButton(); + $show->disableDeleteButton(); + }); + } +} diff --git a/app/Admin/Controllers/Store/DeviceController.php b/app/Admin/Controllers/Store/DeviceController.php new file mode 100644 index 00000000..15006fc9 --- /dev/null +++ b/app/Admin/Controllers/Store/DeviceController.php @@ -0,0 +1,99 @@ +model()->orderBy('id', 'desc'); + + $grid->column('store_id')->display(fn () => data_get($this->store, 'title')); + $grid->column('name'); + $grid->column('device_no'); + $grid->column('status')->switch(); + $grid->column('remarks')->editable(); + + $user = Admin::user(); + + $grid->showViewButton($user->can('dcat.admin.store.device.show')); + $grid->showCreateButton($user->can('dcat.admin.store.device.create')); + $grid->showEditButton($user->can('dcat.admin.store.device.edit')); + $grid->showDeleteButton($user->can('dcat.admin.store.device.destroy')); + + $grid->filter(function (Grid\Filter $filter) { + $filter->panel(); + $filter->equal('store_id')->select('api/store')->width(3); + $filter->where('name', function ($q) { + $input = $this->input; + $q->where(fn($q1) => $q1->where('name', 'like', '%'.$input.'%')->orWhere('device_no', 'like', '%'.$input.'%')); + })->placeholder('名称或者设备编号')->width(3); + }); + }); + } + + protected function form() + { + return Form::make(new Device(), function (Form $form) { + $unique = Rule::unique('store_devices', 'device_no'); + if ($form->isEditing()) { + $unique->ignore($form->getKey()); + } + + $form->select('store_id')->options(Store::pluck('title', 'id'))->required(); + $form->text('name')->required(); + $form->text('device_no')->rules([$unique])->required(); + $form->switch('status')->default(1); + $form->text('remarks'); + + $form->disableCreatingCheck(); + $form->disableEditingCheck(); + $form->disableDeleteButton(); + $form->disableResetButton(); + + $form->deleted(function (Form $form, $result) { + $data = array_column($form->model()->toArray(), 'id'); + // 删除设备记录 + DeviceRecord::whereIn('device_id', $data)->delete(); + }); + }); + } + + protected function detail($id) + { + return Show::make($id, Device::with(['store']), function (Show $show) { + $show->field('id'); + $show->field('store_id'); + $show->field('name'); + $show->field('device_no'); + $show->field('status')->bool(); + $show->field('remarks'); + + $show->disableEditButton(); + $show->disableDeleteButton(); + + $show->relation('records', function ($model) { + $grid = new Grid(new DeviceRecord()); + $grid->model()->where('device_id', $model->id)->orderBy('created_at', 'desc'); + + $grid->column('status')->using(DeviceRecord::$statusMap)->label(DeviceRecord::$statusColor); + $grid->column('data')->display(fn($v) => json_encode($v, JSON_UNESCAPED_UNICODE)); + // $grid->column('result')->display(fn($v) => json_encode($v, JSON_UNESCAPED_UNICODE)); + $grid->column('created_at'); + + $grid->disableActions(); + $grid->disableCreateButton(); + + return $grid; + }); + }); + } +} diff --git a/app/Admin/Controllers/Store/OrderController.php b/app/Admin/Controllers/Store/OrderController.php index fafcf227..7c4470f0 100644 --- a/app/Admin/Controllers/Store/OrderController.php +++ b/app/Admin/Controllers/Store/OrderController.php @@ -194,8 +194,9 @@ class OrderController extends AdminController $show->field('pay_way')->as(function ($v) { return $this->pay_way?->mallText(); })->circleDot(PayWay::colors()); - $show->field('pay_at'); $show->field('created_at'); + $show->field('pay_at'); + $show->field('completed_at'); $show->panel()->tools(function ($tools) { $tools->disableEdit(); diff --git a/app/Admin/Services/OrderPackageService.php b/app/Admin/Services/OrderPackageService.php index ddc23742..44548e8c 100644 --- a/app/Admin/Services/OrderPackageService.php +++ b/app/Admin/Services/OrderPackageService.php @@ -164,4 +164,21 @@ class OrderPackageService ]); } } + + /** + * 订单全部发货 + * + * @param Order $order + * + * @return OrderPackage $package + */ + public function createAll(Order $order, $params = []) + { + $shipping_company = data_get($params, 'shipping_company'); + $shipping_number = data_get($params, 'shipping_number'); + $products = []; + foreach($order->products as $item) { + + } + } } diff --git a/app/Admin/routes.php b/app/Admin/routes.php index 0743a27e..05834f23 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -194,6 +194,8 @@ Route::group([ $router->resource('store/order', 'Store\OrderController')->only(['index', 'show'])->names('store.order'); $router->resource('store/stock', 'Store\StockController')->only(['index', 'create', 'store', 'show'])->names('store.stock'); $router->resource('store/batch', 'Store\StockBatchController')->names('store.batch'); + $router->resource('store/device', 'Store\DeviceController')->names('store.device'); + $router->resource('store/desk', 'Store\DeskController')->names('store.desk'); $router->resource('profit', 'OrderProfitController'); diff --git a/app/Endpoint/Api/Http/Controllers/Order/OrderController.php b/app/Endpoint/Api/Http/Controllers/Order/OrderController.php index b1c22600..34f8bf4f 100644 --- a/app/Endpoint/Api/Http/Controllers/Order/OrderController.php +++ b/app/Endpoint/Api/Http/Controllers/Order/OrderController.php @@ -58,6 +58,10 @@ class OrderController extends Controller 'product.sku_id' => ['bail', 'required', 'int'], 'product.quantity' => ['bail', 'required', 'int', 'min:1'], ], + $request->filled('store_id') => [ + 'products.*.sku_id' => ['bail', 'required', 'int'], + 'products.*.quantity' => ['bail', 'required', 'int', 'min:1'], + ], default => [ 'shopping_cart' => ['bail', 'required', 'array'], ] @@ -77,6 +81,16 @@ class OrderController extends Controller $orderService = new OrderService(); return match (true) { + $request->filled('store_id') => $orderService->createOrderByStore( + $user, + $request->input('store_id'), + $request->input('products'), + [ + 'desk' => $request->input('desk'), + 'note' => $request->input('note'), + 'coupon_id' => $request->input('coupon_id'), + ] + ), $request->filled('order_pre') => $orderService->createOrderByPre($user, OrderPre::findOrFail($request->input('order_pre')), $request->input('coupon_id'), $request->input('note')), $request->filled('product') => $orderService->createQuickOrder( $user, diff --git a/app/Endpoint/Api/Http/Controllers/StoreController.php b/app/Endpoint/Api/Http/Controllers/StoreController.php index c67b4661..a1328f7e 100644 --- a/app/Endpoint/Api/Http/Controllers/StoreController.php +++ b/app/Endpoint/Api/Http/Controllers/StoreController.php @@ -10,6 +10,8 @@ use App\Models\Store\ProductSku as StoreProductSku; use App\Endpoint\Api\Http\Resources\{StoreResource, StoreProductSkuResource, StoreProductSpuResource, ProductSpuResource}; use App\Endpoint\Api\Http\Resources\ProductFeatureResource; use App\Events\ProductSkuViewed; +use App\Models\Store\Desk; +use App\Endpoint\Api\Http\Resources\DeskResource; class StoreController extends Controller { @@ -149,4 +151,10 @@ class StoreController extends Controller return StoreProductSkuResource::make($sku); } + + public function desk($id) + { + $info = Desk::with(['store'])->findOrFail($id); + return DeskResource::make($info); + } } diff --git a/app/Endpoint/Api/Http/Resources/DeskResource.php b/app/Endpoint/Api/Http/Resources/DeskResource.php new file mode 100644 index 00000000..00ab3431 --- /dev/null +++ b/app/Endpoint/Api/Http/Resources/DeskResource.php @@ -0,0 +1,22 @@ + $this->id, + 'extra' => $this->extra, + 'name' => $this->name, + 'remarks' => $this->remarks, + 'status' => $this->status, + 'store_id' => $this->store_id, + 'wxcode' => $this->wxcode, + 'store' => StoreResource::make($this->whenLoaded('store')), + ]; + } +} diff --git a/app/Endpoint/Api/routes.php b/app/Endpoint/Api/routes.php index 057b58ef..f46b3c99 100644 --- a/app/Endpoint/Api/routes.php +++ b/app/Endpoint/Api/routes.php @@ -233,6 +233,9 @@ Route::group([ Route::get('store/{store}/product-sku/{id}', [StoreController::class, 'productSku']); Route::apiResource('store', StoreController::class)->only(['index', 'show']); + // 门店桌号信息 + Route::get('store/desk/{id}', [StoreController::class, 'desk']); + // 门店下单 Route::group(['middleware' => ['auth:api', \App\Endpoint\Api\Http\Middleware\CheckUserStatus::class]], function () { Route::get('order-pre/{id}', [App\Endpoint\Api\Http\Controllers\Order\OrderPreController::class, 'show']); diff --git a/app/Listeners/OrderPrint.php b/app/Listeners/OrderPrint.php new file mode 100644 index 00000000..b0e5e7bb --- /dev/null +++ b/app/Listeners/OrderPrint.php @@ -0,0 +1,64 @@ +order; + // 门店订单, 桌号信息 + if ($order->store_id && $order->source_type == Desk::class) { + $store = $order->store; + $desk = $order->source; + + // 门店设备 + $devices = $store->devices()->where('status', 1)->get(); + $templateId = app_settings('custom.key_value.order_desk_print_template'); + if ($devices->count() > 0 && $templateId) { + $service = PrintService::make(); + $products = []; + foreach($order->products as $item) { + array_push($products, [ + 'name' => $item->name, + 'price' => round($item->sell_price / 100, 2, PHP_ROUND_HALF_DOWN), + 'amount' => $item->quantity, + 'money' => round($item->total_amount / 100, 2, PHP_ROUND_HALF_DOWN), + ]); + } + $data = [ + 'name' => $store->title, + 'sn' => $order->sn, + 'time' => $order->created_at->format('Y-m-d H:i:s'), + 'desk' => $desk->name, + 'products' => $products, + 'total' => round($order->total_amount, 2, PHP_ROUND_HALF_DOWN), + 'remarks' => $order->note, + ]; + foreach($devices as $item) { + $result = $service->template($item->device_no, $templateId, $data); + $status = data_get($result, 'code') == 0 ? DeviceRecord::STATUS_SUCCESS : DeviceRecord::STATUS_FAIL; + // 添加打印的日志记录 + $item->records()->create([ + 'data' => $data, + 'device_id' => $item->id, + 'result' => $result, + 'resource_id' => $order->id, + 'resource_type' => $order->getMorphClass(), + 'status' => $status, + 'store_id' => $store->id + ]); + } + } + } + } +} diff --git a/app/Models/Store/Desk.php b/app/Models/Store/Desk.php new file mode 100644 index 00000000..d5324c26 --- /dev/null +++ b/app/Models/Store/Desk.php @@ -0,0 +1,64 @@ + 'json' + ]; + + public function store() + { + return $this->belongsTo(Store::class, 'store_id'); + } + + public function generateWxCode() + { + $model = $this; + $scene = http_build_query([ + 'd' => $model->id, + 'c' => data_get($model->extra, 'category_id'), + 's' => $model->store_id + ]); + + if (config('app.env') == 'local') { + $url = 'https://ui-avatars.com/api/?name=pd&scene=' . urlencode($scene); + } else { + // 生成小程序码 + $app = \EasyWeChat\Factory::miniProgram(config('wechat.mini_program.default')); + $response = $app->app_code->getUnlimit($scene, [ + 'page' => 'pages/welcome/index', + 'check_path' => false, + // release: 正式版, develop: 开发版, trial: 体验版 + 'env_version' => config('app.debug') ? 'trial' : 'release', + 'width' => 200, + ]); + + // 保存小程序码 + if ($response instanceof StreamResponse) { + $disk = Storage::disk('public'); + $filepath = 'store-desk'; + $filename = $model->id . '.png'; + $response->saveAs($disk->path($filepath), $filename); + $url = $disk->url($filepath . '/' . $filename); + } else { + logger('store-desk 小程序码生成失败', $response); + return $response; + } + } + $model->update(['wxcode' => $url]); + return true; + } +} diff --git a/app/Models/Store/Device.php b/app/Models/Store/Device.php new file mode 100644 index 00000000..538e114a --- /dev/null +++ b/app/Models/Store/Device.php @@ -0,0 +1,34 @@ + 'json' + ]; + + protected $attributes = [ + 'type' => 'print', + 'status' => 1 + ]; + + public function store() + { + return $this->belongsTo(Store::class, 'store_id'); + } + + public function records() + { + return $this->hasMany(DeviceRecord::class, 'device_id'); + } +} diff --git a/app/Models/Store/DeviceRecord.php b/app/Models/Store/DeviceRecord.php new file mode 100644 index 00000000..69a45a14 --- /dev/null +++ b/app/Models/Store/DeviceRecord.php @@ -0,0 +1,51 @@ + 'json', + 'data' => 'json', + ]; + + public static $statusMap = [ + self::STATUS_PROCESSING => '处理中', + self::STATUS_SUCCESS => '成功', + self::STATUS_FAIL => '失败', + ]; + + public static $statusColor = [ + self::STATUS_PROCESSING => 'primary', + self::STATUS_SUCCESS => 'success', + self::STATUS_FAIL => 'danger', + ]; + + public function device() + { + return $this->belongsTo(Device::class, 'device_id'); + } + + public function store() + { + return $this->belongsTo(Store::class, 'store_id'); + } + + public function resource() + { + return $this->morphTo(); + } +} diff --git a/app/Models/Store/Store.php b/app/Models/Store/Store.php index c3eb1484..f8efd42e 100644 --- a/app/Models/Store/Store.php +++ b/app/Models/Store/Store.php @@ -49,6 +49,16 @@ class Store extends Model return $this->hasMany(StockLog::class, 'store_id'); } + public function desks() + { + return $this->hasMany(Desk::class, 'store_id'); + } + + public function devices() + { + return $this->hasMany(Device::class, 'store_id'); + } + public function scopeEffective($q) { return $q->where('status', 1); diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 44a34128..1a6451b3 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -20,7 +20,8 @@ class EventServiceProvider extends ServiceProvider \App\Listeners\OrderPaidNotify::class, \App\Listeners\SendCoupons::class, \App\Listeners\OrderPackage::class, - \App\Listeners\OrderDistribute::class + \App\Listeners\OrderDistribute::class, + \App\Listeners\OrderPrint::class, ], ]; diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index a7e1aa6f..2fd58df4 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -21,7 +21,7 @@ use App\Models\ProductSku; use App\Models\ShippingAddress; use App\Models\SocialiteUser; use App\Models\{User, OrderPre, Tag}; -use App\Models\Store\Store; +use App\Models\Store\{Store, Desk}; use App\Models\UserCoupon; use App\Services\Payment\WxpayService; use Illuminate\Database\Eloquent\Builder; @@ -171,8 +171,7 @@ class OrderService } /** - * 添加店铺订单 - * + * 预订单, 扫码下单 */ public function createOrderByPre(User $user, OrderPre $order_pre, $coupon_id = null, $note = null) { @@ -236,6 +235,100 @@ class OrderService return $order; } + /** + * 门店直接下单 + * + * @param User $user + * @param int $storeId + * @param array $products 商品信息 [{sku_id, quantity}] + * @param array $params {coupon_id: 优惠券id, desk: 桌号id} + * + * @return Order + * @throws BizException + */ + public function createOrderByStore(User $user, $storeId, array $products, array $params = []) + { + $store = Store::find($storeId); + if (!$store) { + throw new BizException('门店不存在'); + } + if (!$store->status) { + throw new BizException('门店: '.$store->title.' 已关闭'); + } + $coupon_id = data_get($params, 'coupon_id'); + $note = data_get($params, 'note'); + $sourceType = Store::class; + $sourceId = $store->id; + + // 桌号下单 + if ($deskId = data_get($params, 'desk')) { + $desk = $store->desks()->find($deskId); + if (!$desk) { + throw new BizException('门店桌号不存在'); + } + if (!$desk->status) { + throw new BizException('门店桌号: '.$desk->name.' 已关闭'); + } + $sourceType = Desk::class; + $sourceId = $desk->id; + } + + // 检查门店商品库存 + $skuList = $store->productSkus; + foreach($products as &$item) { + $sku = $skuList->firstWhere('id', $item['sku_id']); + if (!$sku) { + throw new BizException('门店商品: '.$item->name.' 不存在'); + } + if ($sku->pivot->amount < $item['quantity']) { + throw new BizException('门店商品: '.$item->name.' 库存不足'); + } + $item['sku'] = $sku; + } + + // 优惠券 + $coupon = null; + + if ($coupon_id) { + $coupon = $user->coupons()->onlyAvailable()->lockForUpdate()->findOrFail($coupon_id); + } + + $mapProducts = $this->mapProducts($user, $products, $coupon); + + list($productsTotalAmount, $vipDiscountAmount, $couponDiscountAmount, $salesValue) = $this->calculateFees($mapProducts); + + $order = $this->storeOrder( + $user, + $productsTotalAmount, + $couponDiscountAmount, + $vipDiscountAmount, + 0, + $salesValue, + null, + $note, + $coupon, + null, + $mapProducts + ); + $order->update([ + 'store_id' => $store->id, + 'source_type' => $sourceType, + 'source_id' => $sourceId, + ]); + $this->storeOrderProducts($order, $mapProducts); + + // 将优惠券标记为已使用 + $coupon?->markAsUse(); + + if ($order->total_amount === 0) { + $this->pay($order, PayWay::Balance); + + $order->refresh(); + } + + return $order; + } + /** * 保存订单 * diff --git a/app/Services/PrintService.php b/app/Services/PrintService.php new file mode 100644 index 00000000..1d18edca --- /dev/null +++ b/app/Services/PrintService.php @@ -0,0 +1,88 @@ +memberCode = config('postcom.memberCode'); + $this->apiKey = config('postcom.apiKey'); + } + + /** + * 通过模板打印 + * https://dev.poscom.cn/openapi?templetPrint + * + * @param string $deviceID + * @param string $templetID + * @param array $data + * + * @return array {code: 0(成功), msg: '错误信息'} + */ + public function template($deviceID, $templetID, $data) + { + $result = ['code' => 0, 'msg' => '']; + if (config('app.env') === 'local') { + return $result; + } + $url = 'https://api.poscom.cn/apisc/templetPrint'; + $params = $this->params(['deviceID' => $deviceID]); + $params['templetID'] = $templetID; + $params['tData'] = json_encode($data); + + $response = Http::asForm()->post($url, $params); + if ($response->successful()) { + $result = $response->json(); + } else { + $result['code'] = 1; + $result['msg'] = '请求失败: ' . $response->status(); + } + + return $result; + } + + /** + * 构造请求参数 + * + * @param array $data {deviceID: 终端编号} + * @return array + */ + protected function params($data = []) + { + $reqTime = $this->getMillisecond(); + $deviceID = data_get($data, 'deviceID'); + $memberCode = $this->memberCode; + $msgNo = ''; + $securityCode = md5($memberCode.$deviceID.$msgNo.$reqTime.$this->apiKey); + return [ + 'reqTime' => $reqTime, + 'securityCode' => $securityCode, + 'memberCode' => $memberCode, + 'deviceID' => $deviceID, + ]; + } + + protected function getMillisecond() + { + list($t1, $t2) = explode(' ', microtime()); + return (float)sprintf('%.0f',(floatval($t1)+floatval($t2))*1000); + } + + /** + * @return PrintService + */ + public static function make(...$params) + { + return new static(...$params); + } +} \ No newline at end of file diff --git a/config/postcom.php b/config/postcom.php new file mode 100644 index 00000000..4a94998f --- /dev/null +++ b/config/postcom.php @@ -0,0 +1,6 @@ + env('POSTCOM_MEMBER_CODE'), + 'api_key' => env('POSTCOM_API_KEY'), +]; diff --git a/database/factories/StoreDeviceFactory.php b/database/factories/StoreDeviceFactory.php new file mode 100644 index 00000000..2bd59660 --- /dev/null +++ b/database/factories/StoreDeviceFactory.php @@ -0,0 +1,27 @@ +faker->isbn10(); + } while(Device::where('device_no', $code)->exists()); + return [ + 'device_no' => $code, + 'name' => $code, + 'store_id' => Store::inRandomOrder()->value('id') + ]; + } +} diff --git a/database/factories/StoreDeviceRecordFactory.php b/database/factories/StoreDeviceRecordFactory.php new file mode 100644 index 00000000..4455cc69 --- /dev/null +++ b/database/factories/StoreDeviceRecordFactory.php @@ -0,0 +1,36 @@ +first(); + $status = $this->faker->randomElement([DeviceRecord::STATUS_SUCCESS, DeviceRecord::STATUS_FAIL]); + $data = [ + 'title' => $this->faker->word(), + 'description' => $this->faker->sentence(), + 'content' => $this->faker->paragraph(), + ]; + $result_success = ['code' => 0, 'msg' => '成功']; + $result_fail = ['code' => 1, 'msg' => '请求超时']; + return [ + 'data' => $data, + 'device_id' => $device->id, + 'result' => $status ? $result_success : $result_fail, + 'status' => $status, + 'store_id' => $device->store_id, + ]; + } +} diff --git a/database/migrations/2023_02_22_120022_create_print_desk_table.php b/database/migrations/2023_02_22_120022_create_print_desk_table.php new file mode 100644 index 00000000..64c8188b --- /dev/null +++ b/database/migrations/2023_02_22_120022_create_print_desk_table.php @@ -0,0 +1,62 @@ +id(); + $table->unsignedBigInteger('store_id')->comment('门店 stores.id'); + $table->string('type')->default('print')->comment('设备类型(print: 小票打印机)'); + $table->string('name')->comment('设备名称'); + $table->string('device_no')->comment('设备编号'); + $table->unsignedTinyInteger('status')->default(0)->comment('状态(0: 不可用, 1: 可用)'); + $table->string('remarks')->nullable()->comment('备注'); + $table->json('extra')->nullable()->comment('其他配置'); + $table->timestamps(); + }); + + Schema::create('store_device_records', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('store_id')->comment('门店 stores.id'); + $table->unsignedBigInteger('device_id')->comment('设备 store_devices.id'); + $table->json('result')->nullable()->comment('返回的结果'); + $table->json('data')->nullable()->comment('请求内容'); + $table->unsignedTinyInteger('status')->default(0)->comment('状态(0: 处理中, 1: 成功, 2: 失败)'); + $table->nullableMorphs('resource'); + $table->timestamps(); + }); + + Schema::create('store_desks', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('store_id')->comment('门店 stores.id'); + $table->string('name')->comment('名称'); + $table->unsignedTinyInteger('status')->default(0)->comment('状态(0: 不可用, 1: 可用)'); + $table->string('wxcode')->nullable()->comment('小程序码'); + $table->string('remarks')->nullable()->comment('备注'); + $table->json('extra')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('store_devices'); + Schema::dropIfExists('store_device_records'); + Schema::dropIfExists('store_desks'); + } +} diff --git a/database/seeders/StoreDeviceSeeder.php b/database/seeders/StoreDeviceSeeder.php new file mode 100644 index 00000000..78cee90a --- /dev/null +++ b/database/seeders/StoreDeviceSeeder.php @@ -0,0 +1,23 @@ +count(10)->create(); + (new StoreDeviceRecordFactory())->count(100)->create(); + } +} diff --git a/resources/lang/zh_CN/store-desk.php b/resources/lang/zh_CN/store-desk.php new file mode 100644 index 00000000..3ad3ed3d --- /dev/null +++ b/resources/lang/zh_CN/store-desk.php @@ -0,0 +1,20 @@ + [ + 'store' => '门店管理', + 'Desk' => '桌号管理', + 'desk' => '桌号管理', + ], + 'fields' => [ + 'store_id' => '门店', + 'name' => '名称', + 'status' => '状态', + 'remarks' => '备注', + 'extra' => '其他', + 'wxcode' => '小程序码', + 'category_id' => '商品分类' + ], + 'options' => [ + ], +]; diff --git a/resources/lang/zh_CN/store-device.php b/resources/lang/zh_CN/store-device.php new file mode 100644 index 00000000..4ef4befe --- /dev/null +++ b/resources/lang/zh_CN/store-device.php @@ -0,0 +1,22 @@ + [ + 'store' => '门店管理', + 'Device' => '设备管理', + 'device' => '设备管理', + ], + 'fields' => [ + 'store_id' => '门店', + 'name' => '名称', + 'device_no' => '编号', + 'status' => '状态', + 'remarks' => '备注', + 'extra' => '其他', + 'records' => '日志', + 'data' => '发送', + 'result' => '接收', + ], + 'options' => [ + ], +]; diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php index 59cd0d37..3a014d84 100644 --- a/tests/Feature/ExampleTest.php +++ b/tests/Feature/ExampleTest.php @@ -2,11 +2,8 @@ namespace Tests\Feature; -use App\Models\OrderProfit; -use App\Services\DistributeService; -use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Support\Facades\DB; use Tests\TestCase; +use App\Services\PrintService; class ExampleTest extends TestCase { @@ -17,13 +14,17 @@ class ExampleTest extends TestCase */ public function test_example() { - $service = new DistributeService(); - try { - DB::beginTransaction(); - $service->wechatTransfers(OrderProfit::whereIn('id', [1, 5])->get()); - DB::commit(); - } catch (\Exception $e) { - DB::rollBack(); - } + dd(PrintService::make()->template('00596456352258754', 'a4fcc59f40fd438d9afdd4fc2e9b99fc', [ + 'name' => '乡村基', + 'sn' => '20230223133856127032', + 'time' => '2023-02-23 13:38:56', + 'desk' => '10号桌', + 'products' => [ + ['name' => '香草拿铁(大杯)', 'price' => '32.00', 'amount' => '1', 'money' => '32.00'], + ['name' => '西瓜汁(大杯)', 'price' => '18.00', 'amount' => '1', 'money' => '18.00'], + ], + 'total' => '50.00', + 'remarks' => '打包' + ])); } }