Browse Source

线上支付回调

master
weigang 6 years ago
parent
commit
d6d23fdce4
  1. 4
      app/Amqp/Consumer/DevicOrderConsumer.php
  2. 4
      app/Controller/DeviceController.php
  3. 179
      app/Controller/NotifyController.php
  4. 10
      app/Controller/OrderController.php
  5. 1
      app/Controller/PaymentController.php
  6. 35
      app/Controller/TestController.php
  7. 307
      app/Libs/FeiePrintClient.php
  8. 1
      app/Model/OrderMain.php
  9. 29
      app/Model/OrderSalesStatistic.php
  10. 10
      app/Model/SystemConfig.php
  11. 42
      app/Request/OrderOfflineRequest.php
  12. 2
      app/Service/CouponService.php
  13. 2
      app/Service/CouponServiceInterface.php
  14. 45
      app/Service/DeviceServiceImp.php
  15. 3
      app/Service/DeviceServiceInterface.php
  16. 226
      app/Service/FeiePrintService.php
  17. 10
      app/Service/FeiePrintServiceInterface.php
  18. 147
      app/Service/MiniprogramService.php
  19. 9
      app/Service/MiniprogramServiceInterface.php
  20. 21
      app/Service/MqttServiceInterface.php
  21. 48
      app/Service/MqttSpeakerService.php
  22. 107
      app/Service/OrderService.php
  23. 2
      app/Service/OrderServiceInterface.php
  24. 40
      app/TaskWorker/MQTTClientTask.php
  25. 7
      config/autoload/dependencies.php
  26. 5
      config/config.php
  27. 1
      config/routes.php

4
app/Amqp/Consumer/DevicOrderConsumer.php

@ -6,7 +6,7 @@ namespace App\Amqp\Consumer;
use App\Model\Order;
use App\Model\SpeakerDevic;
use App\Service\DeviceServiceInterFace;
use App\Service\DeviceServiceInterface;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
@ -21,7 +21,7 @@ class DevicOrderConsumer extends ConsumerMessage
{
/**
* @Inject
* @var DeviceServiceInterFace
* @var DeviceServiceInterface
*/
protected $deviceService;

4
app/Controller/DeviceController.php

@ -4,7 +4,7 @@ namespace App\Controller;
use Hyperf\Di\Annotation\Inject;
use App\Exception\BusinessException;
use App\Service\DeviceServiceInterFace;
use App\Service\DeviceServiceInterface;
use Hyperf\Validation\ValidationException;
class DeviceController extends BaseController
@ -12,7 +12,7 @@ class DeviceController extends BaseController
/**
* @Inject
* @var DeviceServiceInterFace
* @var DeviceServiceInterface
*/
protected $deviceService;

179
app/Controller/NotifyController.php

@ -3,46 +3,114 @@
namespace App\Controller;
use App\Constants\LogLabel;
use App\Model\Goods;
use App\Model\Order;
use App\Model\OrderGoods;
use App\Model\OrderMain;
use App\Model\OrderSalesStatistic;
use App\Model\SpecCombination;
use App\Model\Store;
use App\Model\SystemConfig;
use App\Service\DeviceServiceInterface;
use App\Service\FeiePrintServiceInterface;
use App\Service\MiniprogramService;
use App\Service\MqttServiceInterface;
use EasyWeChat\Factory;
use Hyperf\DbConnection\Db;
use Hyperf\Guzzle\CoroutineHandler;
use Exception;
use Hyperf\Di\Annotation\Inject;
class NotifyController extends BaseController
{
/**
* @Inject
* @var MqttServiceInterface
*/
protected $mqttSpeakerService;
/**
* @Inject
* @var DeviceServiceInterface
*/
protected $deviceService;
/**
* @Inject
* @var MiniprogramService
*/
protected $miniprogramService;
/**
* @Inject
* @var FeiePrintServiceInterface
*/
protected $feiePrintService;
public function wxminiOnline()
{
$config = config('wxpay');
$app = Factory::payment($config);
$app['guzzle_handler'] = CoroutineHandler::class;
var_dump('inside');
// 通知回调,进行业务处理
$response = $app->handlePaidNotify(function ($message, $fail) use ($app) {
Db::beginTransaction();
try {
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
$message
);
Db::beginTransaction();
try {
$response = $app->handlePaidNotify(function ($message, $fail) use ($app) {
var_dump('message', $message);
// 支付失败或者通知失败
if (
empty($message)
|| $message['return_code'] != 'SUCCESS'
|| !isset($message['result_code'])
|| $message['result_code'] != 'SUCCESS'
) {
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
$message
);
$fail('Unknown error but FAIL');
}
// 查询订单
$orderMain = OrderMain::query()
->where(['global_order_id' => $message['out_trade_no'], 'type' => OrderMain::ORDER_TYPE_ONLINE, 'state' => OrderMain::ORDER_STATE_UNPAY])
->where('time', '>=', date('Y-m-d H:i:s', (time()-900)))
->where([
'global_order_id' => $message['out_trade_no'],
'type' => OrderMain::ORDER_TYPE_ONLINE,
'state' => OrderMain::ORDER_STATE_UNPAY
])
->where('time', '>=', date('Y-m-d H:i:s', (time() - 900)))
->first();
var_dump('$orderMain', $orderMain);
// 订单不存在
if (empty($orderMain)) {
// 去查一下微信订单
$wxOrder = $app->order->queryByOutTradeNumber($orderMain->global_order_id);
$this->log->event(
LogLabel::PAY_NOTIFY_WXMINI,
$wxOrder
$orderMain
);
// 去查一下微信订单,只处理未支付的情况 TODO 其他情况处理
$wxOrder = $app->order->queryByOutTradeNumber($message['out_trade_no']);
// 查询成功
if ($wxOrder['return_code'] == 'SUCCESS') {
if ($wxOrder['result_code'] == 'SUCCESS') {
// 看订单支付状态,处理未支付的情况,把订单处理成未支付
if ($wxOrder['trade_state'] != 'NOTPAY') {
OrderMain::query()
->where(['global_order_id' => $message['out_trade_no']])
->update(['state' => OrderMain::ORDER_STATE_UNPAY]);
$fail('Order not paid');
}
}
}
// return true;
}
@ -53,25 +121,86 @@ class NotifyController extends BaseController
$orderMain->pay_time = date('Y-m-d H:i:s', $currentTime);
$orderMain->save();
// 更新销量、商品库存,新增月销数据
$upOrder = Order::query()
->where(['order_main_id' => $orderMain->id])
->update(['state' => OrderMain::ORDER_STATE_UNTAKE, 'pay_time' => $orderMain->pay_time]);
// 更新商户销量
$upStoreScore = Store::query()
->whereIn('id', $orderMain->order_ids)
->update(['score' => Db::raw('score+1')]);
// 更新商品库存和销量
$orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'createtime'])
->where(['order_main_id' => $orderMain->id])
->get()
->toArray();
$orderGoods = OrderGoods::query()->select(['good_id AS id', 'number', 'combination_id'])
->whereIn('order_id', array_values(array_column($orders, 'id')))
->get()
->toArray();
foreach ($orderGoods as $key => &$goodsItem) {
$goods = Goods::find($goodsItem['id']);
// 库存处理,有规格
if ($goodsItem->combination_id) {
$combination = SpecCombination::find($goodsItem['combination_id']);
$combination->number = $combination->number - $goodsItem['number'];
$combination->save();
} else {
$goods->inventory = $goods->inventory - $goodsItem['number'];
}
$goods->sales = $goods->sales - $goodsItem['number'];
$goods->save();
}
// 月销流水
$statistics = [];
foreach ($orders as $key => & $order) {
$statistics[] = [
'money' => $order->money,
'user_id' => $order->user_id,
'store_id' => $order->store_id,
'market_id' => $orderMain->market_id,
'order_id' => $order->id,
'createtime' => strtotime($order->pay_time),
];
}
if (is_array($statistics) && !empty($statistics)) {
$inSalesStatistics = OrderSalesStatistic::query()->insert($statistics);
}
// 喇叭通知,兼容旧音响,MQTT+IOT
$res = $this->mqttSpeakerService->speakToStore($orderMain->id);
var_dump($res);
$res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->id);
var_dump($res);
// 公众号模板消息
$res = $this->miniprogramService->sendTemMsgForOnlineOrder($orderMain->id);
var_dump($res);
// 打印订单
// 打印订单,自动打印 TODO 后续优化调用逻辑
$res = $this->feiePrintService->feiePrint($orderMain->order_num);
var_dump($res);
Db::commit();
return true;
});
} catch (Exception $e) {
var_dump('$response', $response);
Db::rollBack();
$response->send();
Db::rollBack();
}
} catch (\EasyWeChat\Kernel\Exceptions\Exception $e) {
});
var_dump($e->getMessage());
Db::rollBack();
}
$response->send();
}
public function wxminiOffline()

10
app/Controller/OrderController.php

@ -3,6 +3,7 @@
namespace App\Controller;
use App\Constants\ErrorCode;
use App\Request\OrderOfflineRequest;
use App\Request\OrderOnlineRequest;
use Hyperf\Di\Annotation\Inject;
use App\Service\OrderServiceInterface;
@ -25,4 +26,13 @@ class OrderController extends BaseController
}
return $this->success(['order_id' => $orderMainId]);
}
public function addOfflineOrder(OrderOfflineRequest $request)
{
$orderMainId = $this->orderService->addOfflineOrder($request->validated());
if (!is_int($orderMainId)) {
return $this->result(ErrorCode::ORDER_FAILURE, '', $orderMainId);
}
return $this->success(['order_id' => $orderMainId]);
}
}

1
app/Controller/PaymentController.php

@ -65,7 +65,6 @@ class PaymentController extends BaseController
// 待支付的,未超时(15min,900sec)的订单
$orderMain = OrderMain::query()
->where(['dm_state' => OrderMain::ORDER_STATE_UNPAY, 'id' => $data['order_id']])
->where('time', '>=', date('Y-m-d H:i:s', (time()-900)))
->first();
if (empty($orderMain)) {

35
app/Controller/TestController.php

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Controller;
use App\Libs\FeiePrintClient;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\Utils\Coroutine;
@ -22,6 +23,7 @@ class TestController extends AbstractController
{
private $name = 'default action';
protected $client = null;
public function index1(RequestInterface $request)
{
@ -37,14 +39,33 @@ class TestController extends AbstractController
// $result = $client->handle("set");
//$log = ApplicationContext::getContainer()->get(Log::class);
$log = $this->log;
// //$log = ApplicationContext::getContainer()->get(Log::class);
// $log = $this->log;
//
// $log->push(['test'=>1,'user_id'=>290,'msg'=>'order']);
// $log->event('t1',['test'=>1,'user_id'=>290,'msg'=>'order']);
//
// //$this->name = 'index1 action '. $result;
// return $this->name;
$log->push(['test'=>1,'user_id'=>290,'msg'=>'order']);
$log->event('t1',['test'=>1,'user_id'=>290,'msg'=>'order']);
//$this->name = 'index1 action '. $result;
return $this->name;
$time = time();
$msgInfo = array(
'user' => '13161443713@163.com',
'stime' => $time,
'sig' => sha1('13161443713@163.com' . 'XsaHzgePdyWTfcMX' . $time),
'apiname' => 'Open_printMsg',
'sn' => '920527381',
'content' => '1111',
'times' => 1//打印次数
);
$this->client = new FeiePrintClient('api.feieyun.cn', 80);
if (!$this->client->post('/Api/Open/', $msgInfo)) {
return '12';
} else {
//服务器返回的JSON字符串,建议要当做日志记录起来
$result = $this->client->getContent();
return $result;
}
}
public function index2(RequestInterface $request)

307
app/Libs/FeiePrintClient.php

@ -0,0 +1,307 @@
<?php
namespace App\Libs;
class FeiePrintClient {
// Request vars
var $host;
var $port;
var $path;
var $method;
var $postdata = '';
var $cookies = array();
var $referer;
var $accept = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
var $accept_encoding = 'gzip';
var $accept_language = 'en-us';
var $user_agent = 'Incutio HttpClient v0.9';
var $timeout = 20;
var $use_gzip = true;
var $persist_cookies = true;
var $persist_referers = true;
var $debug = false;
var $handle_redirects = true;
var $max_redirects = 5;
var $headers_only = false;
var $username;
var $password;
var $status;
var $headers = array();
var $content = '';
var $errormsg;
var $redirect_count = 0;
var $cookie_host = '';
function __construct($host, $port=80) {
$this->host = $host;
$this->port = $port;
}
function get($path, $data = false) {
$this->path = $path;
$this->method = 'GET';
if ($data) {
$this->path .= '?'.$this->buildQueryString($data);
}
return $this->doRequest();
}
function post($path, $data) {
$this->path = $path;
$this->method = 'POST';
$this->postdata = $this->buildQueryString($data);
return $this->doRequest();
}
function buildQueryString($data) {
$querystring = '';
if (is_array($data)) {
foreach ($data as $key => $val) {
if (is_array($val)) {
foreach ($val as $val2) {
$querystring .= urlencode($key).'='.urlencode($val2).'&';
}
} else {
$querystring .= urlencode($key).'='.urlencode($val).'&';
}
}
$querystring = substr($querystring, 0, -1); // Eliminate unnecessary &
} else {
$querystring = $data;
}
return $querystring;
}
function doRequest() {
if (!$fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout)) {
switch($errno) {
case -3:
$this->errormsg = 'Socket creation failed (-3)';
case -4:
$this->errormsg = 'DNS lookup failure (-4)';
case -5:
$this->errormsg = 'Connection refused or timed out (-5)';
default:
$this->errormsg = 'Connection failed ('.$errno.')';
$this->errormsg .= ' '.$errstr;
$this->debug($this->errormsg);
}
return false;
}
socket_set_timeout($fp, $this->timeout);
$request = $this->buildRequest();
$this->debug('Request', $request);
fwrite($fp, $request);
$this->headers = array();
$this->content = '';
$this->errormsg = '';
$inHeaders = true;
$atStart = true;
while (!feof($fp)) {
$line = fgets($fp, 4096);
if ($atStart) {
$atStart = false;
if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m)) {
$this->errormsg = "Status code line invalid: ".htmlentities($line);
$this->debug($this->errormsg);
return false;
}
$http_version = $m[1];
$this->status = $m[2];
$status_string = $m[3];
$this->debug(trim($line));
continue;
}
if ($inHeaders) {
if (trim($line) == '') {
$inHeaders = false;
$this->debug('Received Headers', $this->headers);
if ($this->headers_only) {
break;
}
continue;
}
if (!preg_match('/([^:]+):\\s*(.*)/', $line, $m)) {
continue;
}
$key = strtolower(trim($m[1]));
$val = trim($m[2]);
if (isset($this->headers[$key])) {
if (is_array($this->headers[$key])) {
$this->headers[$key][] = $val;
} else {
$this->headers[$key] = array($this->headers[$key], $val);
}
} else {
$this->headers[$key] = $val;
}
continue;
}
$this->content .= $line;
}
fclose($fp);
if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] == 'gzip') {
$this->debug('Content is gzip encoded, unzipping it');
$this->content = substr($this->content, 10);
$this->content = gzinflate($this->content);
}
if ($this->persist_cookies && isset($this->headers['set-cookie']) && $this->host == $this->cookie_host) {
$cookies = $this->headers['set-cookie'];
if (!is_array($cookies)) {
$cookies = array($cookies);
}
foreach ($cookies as $cookie) {
if (preg_match('/([^=]+)=([^;]+);/', $cookie, $m)) {
$this->cookies[$m[1]] = $m[2];
}
}
$this->cookie_host = $this->host;
}
if ($this->persist_referers) {
$this->debug('Persisting referer: '.$this->getRequestURL());
$this->referer = $this->getRequestURL();
}
if ($this->handle_redirects) {
if (++$this->redirect_count >= $this->max_redirects) {
$this->errormsg = 'Number of redirects exceeded maximum ('.$this->max_redirects.')';
$this->debug($this->errormsg);
$this->redirect_count = 0;
return false;
}
$location = isset($this->headers['location']) ? $this->headers['location'] : '';
$uri = isset($this->headers['uri']) ? $this->headers['uri'] : '';
if ($location || $uri) {
$url = parse_url($location.$uri);
return $this->get($url['path']);
}
}
return true;
}
function buildRequest() {
$headers = array();
$headers[] = "{$this->method} {$this->path} HTTP/1.0";
$headers[] = "Host: {$this->host}";
$headers[] = "User-Agent: {$this->user_agent}";
$headers[] = "Accept: {$this->accept}";
if ($this->use_gzip) {
$headers[] = "Accept-encoding: {$this->accept_encoding}";
}
$headers[] = "Accept-language: {$this->accept_language}";
if ($this->referer) {
$headers[] = "Referer: {$this->referer}";
}
if ($this->cookies) {
$cookie = 'Cookie: ';
foreach ($this->cookies as $key => $value) {
$cookie .= "$key=$value; ";
}
$headers[] = $cookie;
}
if ($this->username && $this->password) {
$headers[] = 'Authorization: BASIC '.base64_encode($this->username.':'.$this->password);
}
if ($this->postdata) {
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
$headers[] = 'Content-Length: '.strlen($this->postdata);
}
$request = implode("\r\n", $headers)."\r\n\r\n".$this->postdata;
return $request;
}
function getStatus() {
return $this->status;
}
function getContent() {
return $this->content;
}
function getHeaders() {
return $this->headers;
}
function getHeader($header) {
$header = strtolower($header);
if (isset($this->headers[$header])) {
return $this->headers[$header];
} else {
return false;
}
}
function getError() {
return $this->errormsg;
}
function getCookies() {
return $this->cookies;
}
function getRequestURL() {
$url = 'https://'.$this->host;
if ($this->port != 80) {
$url .= ':'.$this->port;
}
$url .= $this->path;
return $url;
}
function setUserAgent($string) {
$this->user_agent = $string;
}
function setAuthorization($username, $password) {
$this->username = $username;
$this->password = $password;
}
function setCookies($array) {
$this->cookies = $array;
}
function useGzip($boolean) {
$this->use_gzip = $boolean;
}
function setPersistCookies($boolean) {
$this->persist_cookies = $boolean;
}
function setPersistReferers($boolean) {
$this->persist_referers = $boolean;
}
function setHandleRedirects($boolean) {
$this->handle_redirects = $boolean;
}
function setMaxRedirects($num) {
$this->max_redirects = $num;
}
function setHeadersOnly($boolean) {
$this->headers_only = $boolean;
}
function setDebug($boolean) {
$this->debug = $boolean;
}
function quickGet($url) {
$bits = parse_url($url);
$host = $bits['host'];
$port = isset($bits['port']) ? $bits['port'] : 80;
$path = isset($bits['path']) ? $bits['path'] : '/';
if (isset($bits['query'])) {
$path .= '?'.$bits['query'];
}
$client = new HttpClient($host, $port);
if (!$client->get($path)) {
return false;
} else {
return $client->getContent();
}
}
function quickPost($url, $data) {
$bits = parse_url($url);
$host = $bits['host'];
$port = isset($bits['port']) ? $bits['port'] : 80;
$path = isset($bits['path']) ? $bits['path'] : '/';
$client = new HttpClient($host, $port);
if (!$client->post($path, $data)) {
return false;
} else {
return $client->getContent();
}
}
function debug($msg, $object = false) {
if ($this->debug) {
print '<div style="border: 1px solid red; padding: 0.5em; margin: 0.5em;"><strong>HttpClient Debug:</strong> '.$msg;
if ($object) {
ob_start();
print_r($object);
$content = htmlentities(ob_get_contents());
ob_end_clean();
print '<pre>'.$content.'</pre>';
}
print '</div>';
}
}
}

1
app/Model/OrderMain.php

@ -75,6 +75,7 @@ class OrderMain extends Model
'coupon_id2',
'uniacid',
'state',
'dm_state',
'time',
'time_add',
'pay_time',

29
app/Model/OrderSalesStatistic.php

@ -0,0 +1,29 @@
<?php
declare (strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
/**
*/
class OrderSalesStatistic extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'ims_cjdc_order_sales_statistics';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [];
}

10
app/Model/SystemConfig.php

@ -0,0 +1,10 @@
<?php
namespace App\Model;
class SystemConfig extends Model
{
protected $table = 'ims_cjdc_system_config';
}

42
app/Request/OrderOfflineRequest.php

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace App\Request;
class OrderOfflineRequest extends BaseFormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'store_id' => 'required|nonempty|integer',
'user_id' => 'required|nonempty|integer',
'money' => 'required|nonempty',
];
}
public function messages(): array
{
return [
'*.*' => ':attribute 参数异常'
];
}
public function attributes(): array
{
return [
];
}
}

2
app/Service/CouponService.php

@ -6,7 +6,7 @@ use Hyperf\DbConnection\Db;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
class CouponService implements CoupnoServiceInterface
class CouponService implements CouponServiceInterface
{
/**

2
app/Service/CoupnoServiceInterface.php → app/Service/CouponServiceInterface.php

@ -4,7 +4,7 @@
namespace App\Service;
interface CoupnoServiceInterface
interface CouponServiceInterface
{
/**
* 当前订单可用优惠券列表

45
app/Service/DeviceServiceImp.php

@ -4,13 +4,14 @@ namespace App\Service;
use App\Commons\Log;
use App\Constants\LogLabel;
use App\Model\Order;
use App\Model\SpeakerDevic;
use App\Model\Store;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\ApplicationContext;
use App\TaskWorker\AliIotTask;
class DeviceServiceImp implements DeviceServiceInterFace
class DeviceServiceImp implements DeviceServiceInterface
{
/**
* @Inject
@ -54,13 +55,6 @@ class DeviceServiceImp implements DeviceServiceInterFace
// 获取市场ID
$market_id = Store::query()->where(['id' => $store_id])->value('market_id');
// $sd = new SpeakerDevic;
// $sd->store_id = $store_id;
// $sd->device_name = $dev_name;
// $sd->market_id = $market_id;
// $sd->bind_time = time();
// $sd->saveOrFail();
$sd = SpeakerDevic::query()->updateOrCreate(
['store_id' => $store_id, 'device_name' => $dev_name],
['market_id' => $market_id, 'bind_time' => time(), 'is_bind' => SpeakerDevic::IS_BIND_YES]
@ -84,8 +78,9 @@ class DeviceServiceImp implements DeviceServiceInterFace
/**
* 发布语音消息
* @param $store_id
* @param $dev_names
* @param $msg
* @return bool
*/
public function pubMsgToStoreByDevName($dev_names, $msg)
{
@ -96,6 +91,38 @@ class DeviceServiceImp implements DeviceServiceInterFace
return true;
}
public function pubMsgToStoreByOrderMainId($order_id, $is_main = true)
{
// 获取订单
$orders = Order::query()->select(['id','order_num','money', 'pay_type', 'store_id', 'type']);
if ($is_main) {
$orders = $orders->where(['order_main_id' => $order_id])->get()->toArray();
} else {
$orders = $orders->where(['id' => $order_id])->get()->toArray();
}
if(empty($orders)) return;
// 循环发送
foreach ($orders as $k => &$order) {
$device_names = SpeakerDevic::query()
->select(['device_name'])
->where(['store_id' => $order['store_id'], 'is_bind' => SpeakerDevic::IS_BIND_YES])
->get()
->toArray();
$msg = "{\"msg\":\"到账".$order['money']."\"}";
foreach ($device_names as $key => $dev_name) {
$this->IOTService->pub($dev_name['device_name'], $msg);
}
}
return true;
}
/**
* 当前设备是否已经被绑定
* @param $dev_name

3
app/Service/DeviceServiceInterFace.php → app/Service/DeviceServiceInterface.php

@ -2,10 +2,11 @@
namespace App\Service;
interface DeviceServiceInterFace
interface DeviceServiceInterface
{
public function getListByStoreId($store_id);
public function bindByStoreId($dev_name,$store_id);
public function unbindById($bind_id);
public function pubMsgToStoreByDevName($dev_names,$msg);
public function pubMsgToStoreByOrderMainId($order_id, $is_main = true);
}

226
app/Service/FeiePrintService.php

@ -0,0 +1,226 @@
<?php
namespace App\Service;
use App\Libs\FeiePrintClient;
use Hyperf\DbConnection\Db;
use Hyperf\Utils\ApplicationContext;
class FeiePrintService implements FeiePrintServiceInterface
{
// *必填*:飞鹅云后台注册账号
const USER = '13161443713@163.com';
// *必填*: 飞鹅云后台注册账号后生成的UKEY 【备注:这不是填打印机的KEY】
const UKEY = 'XsaHzgePdyWTfcMX';
// *必填*:打印机编号,必须要在管理后台里添加打印机或调用API接口添加之后,才能调用API
const SN = '550510805';
// 以下参数不需要修改
// 接口IP或域名
const IP = 'api.feieyun.cn';
// 接口IP端口
const PORT = 80;
// 接口路径
const PATH = '/Api/Open/';
public function feiePrint($order_num)
{
$data = Db::table('ims_cjdc_order_main as m')
->join('ims_cjdc_order as o','o.order_main_id', '=', 'm.id','inner')
->join('ims_cjdc_order_goods as g','o.id','=', 'g.order_id','inner')
->join('ims_cjdc_feprint as f','m.market_id','=', 'f.market_id','inner')
->join('ims_cjdc_store as s','s.id','=', 'o.store_id','inner')
->where('m.order_num', $order_num)
->select("o.note as o_note,g.name,g.number,g.money,g.good_unit,m.delivery_time as ps_time,m.address,m.note,m.name as user_name,m.dada_fee,m.money as m_money,m.yhq_money2,m.box_money,f.sn,m.tel,m.order_num,g.id,g.spec,s.name as shopname")
->order('s.id')
->get();
$content = $this->printFormat($data, 14, 6, 3, 6);
$res = $this->printMsg($data[0]['sn'], $content, 1);
return ($res);
}
/**
* [打印订单接口 Open_printMsg]
* @param [string] $sn [打印机编号sn]
* @param [string] $content [打印内容]
* @param [string] $times [打印联数]
* @return [string] [接口返回值]
*/
protected function printMsg($sn, $content, $times = 1)
{
$time = time(); //请求时间
$msgInfo = array(
'user' => self::USER,
'stime' => $time,
'sig' => sha1(self::USER . self::UKEY . $time),
'apiname' => 'Open_printMsg',
'sn' => $sn,
'content' => $content,
'times' => $times//打印次数
);
$client = new FeiePrintClient(self::IP, self::PORT);
if (!$client->post(self::PATH, $msgInfo)) {
echo 'error';
} else {
// 服务器返回的JSON字符串,建议要当做日志记录起来
$result = $client->getContent();
return $result;
}
}
protected function printFormat($arr, $A, $B, $C, $D)
{
$orderInfo = '<CB>懒族生活</CB><BR>';
$orderInfo .= '名称 单价 数量 金额<BR>';
$orderInfo .= '--------------------------------<BR>';
$shopname = "";
$shopnum = 0;
foreach ($arr as $k5 => $v5) {
if ($shopname != $v5['shopname']) {
if ($shopname != "") {
$orderInfo .= ' <BR>';
}
$shopnum++;
$orderInfo .= "<C>(" . $shopnum . ")" .$v5['shopname'] . '</C><BR>';
$shopname = $v5['shopname'];
}
$name = $v5['name'];
if(!empty($v5['spec'])) {
$name .= "(规格:". $v5['spec'].")";
}elseif (!empty($v5['good_unit'])){
$name .= "(规格:". $v5['good_unit'].")";
}
$price = $v5['money'];
$num = $v5['number'];
$prices = sprintf("%.2f",$v5['money']*$v5['number']);
$kw3 = '';
$kw1 = '';
$kw2 = '';
$kw4 = '';
$str = $name;
$blankNum = $A;//名称控制为14个字节
$lan = mb_strlen($str,'utf-8');
$m = 0;
$j=1;
$blankNum++;
$result = array();
if(strlen($price) < $B){
$k1 = $B - strlen($price);
for($q=0;$q<$k1;$q++){
$kw1 .= ' ';
}
$price = $kw1.$price;
}
if(strlen($num) < $C){
$k2 = $C - strlen($num);
for($q=0;$q<$k2;$q++){
$kw2 .= ' ';
}
$num = $kw2.$num;
}
if(strlen($prices) < $D){
$k3 = $D - strlen($prices);
for($q=0;$q<$k3;$q++){
$kw4 .= ' ';
}
$prices = $kw4.$prices;
}
for ($i=0;$i<$lan;$i++){
$new = mb_substr($str,$m,$j,'utf-8');
$j++;
if(mb_strwidth($new,'utf-8')<$blankNum) {
if($m+$j>$lan) {
$m = $m+$j;
$tail = $new;
$lenght = iconv("UTF-8", "GBK//IGNORE", $new);
$k = $A - strlen($lenght);
for($q=0;$q<$k;$q++){
$kw3 .= ' ';
}
if($m==$j){
$tail .= $kw3.' '.$price.' '.$num.' '.$prices;
}else{
$tail .= $kw3.'<BR>';
}
break;
}else{
$next_new = mb_substr($str,$m,$j,'utf-8');
if(mb_strwidth($next_new,'utf-8')<$blankNum) continue;
else{
$m = $i+1;
$result[] = $new;
$j=1;
}
}
}
}
$head = '';
foreach ($result as $key=>$value) {
if($key < 1){
$v_lenght = iconv("UTF-8", "GBK//IGNORE", $value);
$v_lenght = strlen($v_lenght);
if($v_lenght == 13) $value = $value." ";
$head .= $value.' '.$price.' '.$num.' '.$prices;
}else{
$head .= $value.'<BR>';
}
}
$orderInfo .= $head.$tail;
if(!empty($v5['o_note'])){
$orderInfo .= '备注:'.$v5['o_note'].'<BR>';
}
}
// $time = date('Y-m-d H:i:s', time());
$orderInfo .= '--------------------------------<BR>';
if ($arr[0]['box_money'] > 0) {
$kw5 = '';
$len = 24 - strlen($arr[0]['box_money']);
for ($q = 0; $q < $len; $q++) {
$kw5 .= ' ';
}
$orderInfo .= '包装费:' . $kw5 . $arr[0]['box_money'] . '<BR>';
}
if($arr[0]['dada_fee'] > 0){
$kw5 = '';
$len = 24 - strlen($arr[0]['dada_fee']);
for ($q = 0; $q < $len; $q++) {
$kw5 .= ' ';
}
$orderInfo .= '配送费:'.$kw5.$arr[0]['dada_fee'].'<BR>';
}
if($arr[0]['yhq_money2'] > 0){
$yhq_money2 = sprintf("%.2f",$arr[0]['yhq_money2']);
$kw6 = '';
$len = 25 - strlen($yhq_money2);
for ($q = 0; $q < $len; $q++) {
$kw6 .= ' ';
}
$orderInfo .= '红包:'.$kw6.'-'.$yhq_money2.'<BR>';
}
$total = '合计:'.$arr[0]['m_money'];
$user_name = $arr[0]['user_name'];
if(strlen($user_name)>18){
$user_name=substr($user_name,0,18).'...';
}
$str = $user_name . $total;
$kw5 = '';
$lenght = iconv("UTF-8", "GBK//IGNORE", $str);
$total_len = 32 - strlen($lenght);
for ($q = 0; $q < $total_len; $q++) {
$kw5 .= ' ';
}
$total_str = $user_name.$kw5.$total;
$orderInfo .= $total_str.'<BR>';
$orderInfo .= '送货地点:' . $arr[0]['address'] . '<BR>';
$tel = substr_replace( $arr[0]['tel'], '****', 3, 4);
$orderInfo .= '联系电话:' . $tel . '<BR>';
$orderInfo .= '配送时间:' . $arr[0]['ps_time'] . '<BR>';
if(!empty($arr[0]['note'])){
$orderInfo .= '备注:'.$arr[0]['note'].'<BR><BR>';
}
//$orderInfo .= '<QR>http://www.feieyun.com</QR>';//把解析后的二维码生成的字符串用标签套上即可自动生成二维码
return $orderInfo;
}
}

10
app/Service/FeiePrintServiceInterface.php

@ -0,0 +1,10 @@
<?php
namespace App\Service;
interface FeiePrintServiceInterface
{
public function feiePrint($order_num);
}

147
app/Service/MiniprogramService.php

@ -0,0 +1,147 @@
<?php
namespace App\Service;
use App\Model\Order;
use App\Model\OrderGoods;
use App\Model\OrderMain;
use App\Model\Store;
use App\Model\Users;
use EasyWeChat\Factory;
class MiniprogramService implements MiniprogramServiceInterface
{
public function sendTemMsgForOnlineOrder($order_main_id)
{
// 查询订单信息
$order = OrderMain::find($order_main_id);
$payTypes = ['1' => '微信支付', '2' => '余额支付', '3' => '积分支付', '4' => '货到付款'];
$address_store = $order['address'] . ';' .$order['name']. ';'. substr_replace($order['tel'],'****',3,4);
$address = $order['address'] . ';' .$order['name']. ';'. $order['tel'];
// 查询子订单,用于发消息给商户
$order_children = Order::query()->select(['id', 'order_num', 'store_id', 'money', 'time'])
->where(['order_main_id' => $order_main_id])
->get()
->toArray();
$goods_temp_all = [];
foreach ($order_children as $key => &$item) {
$item = (array)$item;
// 订单商品
$order_goods = OrderGoods::query()->select(['name', 'number', 'spec', 'good_unit'])
->where(['order_id' => $item['id']])
->get()
->toArray();
$goods_temp = [];
foreach ($order_goods as $k => &$goods) {
array_push($goods_temp, $goods['name']."*".$goods['number']."/".($goods['spec']?:$goods['good_unit']));
array_push($goods_temp_all, $goods['name']."*".$goods['number']."/".($goods['spec']?:$goods['good_unit']));
}
// 商户/门店的openid
$store = Store::query()->select(['id', 'name'])
->where(['id' => $item['store_id']])
->first()->toArray();
$store['openid'] = Users::query()
->where(['id' => $store['user_id']])
->value('openid');
// 模板数据
$data_store = [
'first' => ['您有新的外卖订单!订单编号:'.$item['order_num'], '#ff0000'],
'keyword' => [
["您的外卖订单详情:\r\n".implode(";\r\n",$goods_temp), '#ff0000'],
$item['money'],
$payTypes[$order['pay_type']],
$item['time']?:'',
$address_store,
],
'remark' => [$order['note'], '#4e6ef2']
];
$ret_store = $this->sendTempMsg($store['openid'], '-M7DG_ACwJxqdAvyvJuAnPpx4xaLf3VkkN0fckno71c',$data_store);
}
// 模板数据发送消息给用户
$data_user = [
'first' => '您好,下单成功!订单编号:'.$order['order_num'],
'keyword' => [
implode(";\r\n", $goods_temp_all),
$order['money'],
$payTypes[$order['pay_type']],
date('Y-m-d H:i:s', $order['time_add']),
$address,
],
'remark' => '感谢您的光临,欢迎下次再来!'
];
// 获取用户openid,发送给用户
$user_openid = Users::query()->where(['id' => $order['user_id']])->value('openid');
$ret_user = $this->sendTempMsg($user_openid,'-M7DG_ACwJxqdAvyvJuAnPpx4xaLf3VkkN0fckno71c', $data_user);
}
public function sendTempMsg($openid, $template_id, $data, $redirect_url = '', $applet_config = ['appid' => '', 'pagepath' => ''])
{
// 先拼个基础的
$template = [
'touser' => $openid,
'mp_template_msg' => [
'appid' => env('OFFICIAL_APP_ID'),
'template_id' => $template_id,
'url' => $redirect_url,
]
];
// 看看有没有小程序跳转的要求
if ( is_array($applet_config)&&!empty($applet_config)&&!empty($applet_config['appid']) ) {
$template['mp_template_msg']['miniprogram'] = $applet_config;
}
// 重点来了,拼接关键数据data
if (!is_array($data)) { # 数组都不是,请回去
return false;
}
if (is_array($data['first'])) {
$template['mp_template_msg']['data']['first']['value'] = $data['first'][0] ?? '';
$template['mp_template_msg']['data']['first']['color'] = $data['first'][1] ?? '';
} else {
$template['mp_template_msg']['data']['first']['value'] = $data['first'];
}
if (isset($data['keyword'])&&is_array($data['keyword'])) {
foreach ($data['keyword'] as $key => &$keyword) {
$index = $key+1;
if (is_array($keyword)) {
$template['mp_template_msg']['data']['keyword'.$index]['value'] = $keyword[0] ?? '';
$template['mp_template_msg']['data']['keyword'.$index]['color'] = $keyword[1] ?? '';
} else {
$template['mp_template_msg']['data']['keyword'.$index]['value'] = $keyword;
}
}
}
if (is_array($data['remark'])) {
$template['mp_template_msg']['data']['remark']['value'] = $data['remark'][0] ?? '';
$template['mp_template_msg']['data']['remark']['color'] = $data['remark'][1] ?? '';
} else {
$template['mp_template_msg']['data']['remark']['value'] = $data['remark'];
}
$app = Factory::miniProgram(config('wxtempmsg'));
$app->uniform_message->send($template);
}
}

9
app/Service/MiniprogramServiceInterface.php

@ -0,0 +1,9 @@
<?php
namespace App\Service;
interface MiniprogramServiceInterface
{
public function sendTemMsgForOnlineOrder($order_main_id);
public function sendTempMsg($openid, $template_id, $data, $redirect_url = '', $applet_config = ['appid' => '', 'pagepath' => '']);
}

21
app/Service/MqttServiceInterface.php

@ -0,0 +1,21 @@
<?php
namespace App\Service;
interface MqttServiceInterface
{
/**
* 发布给商户
* @return mixed
*/
public function speakToStore($orderId, $isMain = true);
/**
* MQTT发布消息
* @param $message
* @param $topic
* @param $toClientId
* @return mixed
*/
public function pubToMqtt($message, $topic, $toClientId);
}

48
app/Service/MqttSpeakerService.php

@ -0,0 +1,48 @@
<?php
namespace App\Service;
use App\Model\Order;
use App\Model\Store;
use App\TaskWorker\MQTTClientTask;
class MqttSpeakerService implements MqttServiceInterface
{
const TOPIC = 'test01';
/**
* @inheritDoc
*/
public function speakToStore($orderId, $isMain = true)
{
// 获取订单
$orders = Order::query()->select(['id','order_num','money', 'pay_type', 'store_id', 'type']);
if ($isMain) {
$orders = $orders->where(['order_main_id' => $orderId])->get()->toArray();
} else {
$orders = $orders->where(['id' => $orderId])->get()->toArray();
}
if(empty($orders)) return;
// 循环发送
foreach ($orders as $k => &$order) {
$order['template'] = "懒族生活支付到账".floatval($order['money'])."";
// 获取终端ID
$order['to_client_id'] = Store::query()->where(['id' => $order['store_id']])->value('loudspeaker_imei');
// 发布订阅消息
$this->pubToMqtt($order['template'], self::TOPIC, $order['to_client_id']);
}
}
/**
* @inheritDoc
*/
public function pubToMqtt($message, $topic, $toClientId)
{
$task = ApplicationContext::getContainer()->get(MQTTClientTask::class);
$task->publish($message, $topic, $toClientId);
}
}

107
app/Service/OrderService.php

@ -22,7 +22,7 @@ class OrderService implements OrderServiceInterface
/**
* @Inject
* @var CoupnoServiceInterface
* @var CouponServiceInterface
*/
protected $couponService;
@ -349,9 +349,110 @@ class OrderService implements OrderServiceInterface
/**
* @inheritDoc
*/
public function addOfflineOrder()
public function addOfflineOrder($data)
{
// TODO: Implement addOfflineOrder() method.
Db::beginTransaction();
try {
// 主订单数据
$dataMain = [];
// 获取分布式全局ID
$generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
$globalRrderId = $generator->generate();
// 主订单插入数据
$currentTime = time();
$dataMain = [
'delivery_no' => '',
'dada_fee' => 0,
'market_id' => 0,
'box_money' => 0,
'ps_money' => 0,
'mj_money' => 0,
'xyh_money' => 0,
'yhq_money' => 0,
'yhq_money2' => 0,
'zk_money' => 0,
'tel' => '',
'name' => '',
'address' => '',
'area' => '',
'lat' => '',
'lng' => '',
'note' => '',
'form_id' => '',
'form_id2' => '',
'delivery_time' => '',
'order_type' => 0,
'coupon_id' => 0,
'coupon_id2' => 0,
'store_list' => '',
'receive_coupon_ids' => '',
'type' => OrderMain::ORDER_TYPE_OFFLINE,
'time' => date('Y-m-d H:i:s', $currentTime),
'time_add' => $currentTime,
'pay_time' => '',
'pay_type' => OrderMain::ORDER_PAY_WX,
'state' => OrderMain::ORDER_STATE_UNPAY,
'dm_state' => OrderMain::ORDER_STATE_UNPAY,
'code' => $globalRrderId,
'jj_note' => '',
'uniacid' => 2,
'order_num' => 'dm'.date('YmdHis', time()) . rand(1111, 9999),
'money' => $data['money'],
'user_id' => $data['user_id'],
'store_ids' => $data['store_id'],
'global_order_id' => $globalRrderId,
];
// 主订单模型保存
$orderMain = OrderMain::create($dataMain);
$orderMainId = $orderMain->id;
// 子订单模型保存
$dataChild = [
'uniacid' => 1,
'order_num' => 's'.date('YmdHis', time()) . rand(1111, 9999),
'user_id' => $orderMain->user_id,
'store_id' => $data['store_id'],
'order_main_id' => $orderMainId,
'state' => OrderMain::ORDER_STATE_UNPAY,
'tel' => $orderMain->tel,
'name' => $orderMain->name,
'address' => $orderMain->address,
'area' => $orderMain->area,
'time' => date("Y-m-d H:i:s"),
'note' => '',
'delivery_time' => $orderMain->delivery_time,
'type' => $orderMain->type,
'lat' => $orderMain->lat,
'lng' => $orderMain->lng,
'pay_type' => $orderMain->pay_type,
'order_type' => $orderMain->order_type,
'money' => 0,
'box_money' => 0,
'mj_money' => 0,
'yhq_money' => 0,
'yhq_money2' => 0,
'zk_money' => 0,
'coupon_id' => 0,
'coupon_id2' => 0,
'xyh_money' => 0,
'time_add' => date("Y-m-d H:i:s"),
'jj_note' => '',
'form_id' => '',
'form_id2' => '',
'code' => '',
];
$orderChildId = Order::query()->insertGetId($dataChild);
Db::commit();
return $orderMainId;
} catch (Exception $e) {
Db::rollBack();
return '购买失败';
}
}

2
app/Service/OrderServiceInterface.php

@ -17,7 +17,7 @@ interface OrderServiceInterface
* 扫码支付
* @return mixed
*/
public function addOfflineOrder();
public function addOfflineOrder($data);
/**
* 订单是否已经存在

40
app/TaskWorker/MQTTClientTask.php

@ -12,8 +12,46 @@ class MQTTClientTask
/**
* @Task
* @param string|number $message 消息内容
* @param string $topic 发布消息到主题,主题名
* @param string $type 消息类型,cash或tts
* @param string $payId 支付方式,如“支付宝”、“微信”等
* @param string $toClientId 终端id,如IMEI码
* @param string $curClientId 当前客户端id
*/
public function getClient()
public function publish(
$message,
$topic,
$toClientId = '',
$type = '',
$payId = '',
$curClientId = ''
) {
$this->getClient();
$msgArr = [];
if ( (empty($type)&&is_numeric($message)) || 'cash' === $type ) {
$msgArr['cash'] = $message;
$payId AND $msgArr['payid'] = $payId;
} else {
$msgArr['message'] = $message;
}
if (!empty($toClientId)) {
$topic .= '/'.$toClientId;
}
$curClientId OR $curClientId = rand(1,999999999);
$success = $this->mqttClient->sendConnect($curClientId);
if ($success) {
$this->mqttClient->sendPublish($topic, json_encode($msgArr), MQTTClient::MQTT_QOS2);
$this->mqttClient->sendDisconnect();
}
$this->mqttClient->close();
}
protected function getClient()
{
$this->mqttClient = new MQTTClient(env('MQTT_HOST'), env('MQTT_PORT'));
$this->mqttClient->setAuthentication(env('MQTT_NAME'), env('MQTT_PASS'));

7
config/autoload/dependencies.php

@ -9,13 +9,16 @@ declare(strict_types=1);
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
\App\Service\ServiceEvaluateServiceInterface::class => \App\Service\ServiceEvaluateService::class,
\App\Service\AttachmentServiceInterface::class => \App\Service\AttachmentService::class,
\App\Service\ParamsTokenServiceInterface::class => \App\Service\ParamsTokenSsdbService::class,
\App\Service\DeviceServiceInterFace::class =>\App\Service\DeviceServiceImp::class,
\App\Service\DeviceServiceInterface::class =>\App\Service\DeviceServiceImp::class,
\App\Commons\Log::class => \App\Commons\Log::class,
\App\Service\IOTServiceInterface::class => \App\Service\IOTAliService::class,
\App\Service\OrderServiceInterface::class => \App\Service\OrderService::class,
\App\Service\CoupnoServiceInterface::class => \App\Service\CouponService::class,
\App\Service\CouponServiceInterface::class => \App\Service\CouponService::class,
\App\Service\MqttServiceInterface::class => \App\Service\MqttSpeakerService::class,
\App\Service\FeiePrintServiceInterface::class => \App\Service\FeiePrintService::class,
];

5
config/config.php

@ -36,6 +36,9 @@ return [
'cert_path' => env('CERT_PATH',''),
'key_path' => env('KEY_PATH',''),
'notify_url' => env('NOTIFY_URL',''),
],
'wxtempmsg' => [
'app_id' => env('APP_ID',''),
'secret' => env('APP_SECRET',''),
]
];

1
config/routes.php

@ -39,6 +39,7 @@ Router::addGroup('/v1/',function (){
//订单相关
Router::post('Order/addOnline', 'App\Controller\OrderController@addOnlineOrder');
Router::post('Order/addOffline', 'App\Controller\OrderController@addOfflineOrder');
//小程序支付相关
Router::post('wxminipay/online', 'App\Controller\PaymentController@wxminiPayOnline');

Loading…
Cancel
Save