import { Init, Inject, Provide } from '@midwayjs/core';
|
import { BaseService, CoolCommException, CoolTransaction } from '@cool-midway/core';
|
import { PluginService } from '../../plugin/service/info';
|
import { OrderInfoService } from './info';
|
import { UserWxService } from '../../user/service/wx';
|
import BigNumber from 'bignumber.js';
|
import { OrderInfoEntity } from '../entity/info';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { QueryRunner, Repository } from 'typeorm';
|
import { Action, OrderQueue } from '../queue/order';
|
import { BaseSysParamService } from '../../base/service/sys/param';
|
import { UserInfoEntity } from '../../user/entity/info';
|
import { RecycleTransactionEntity } from '../../shop/entity/transaction';
|
|
/**
|
* 支付
|
*/
|
@Provide()
|
export class OrderPayService extends BaseService {
|
@InjectEntityModel(OrderInfoEntity)
|
orderInfoEntity: Repository<OrderInfoEntity>;
|
|
@InjectEntityModel(UserInfoEntity)
|
userInfoEntity: Repository<UserInfoEntity>;
|
|
@InjectEntityModel(RecycleTransactionEntity)
|
recycleTransactionEntity: Repository<RecycleTransactionEntity>;
|
|
@Inject()
|
pluginService: PluginService;
|
|
@Inject()
|
orderInfoService: OrderInfoService;
|
|
@Inject()
|
userWxService: UserWxService;
|
|
@Inject()
|
orderQueue: OrderQueue;
|
|
@Inject()
|
baseSysParamService: BaseSysParamService;
|
|
@Init()
|
async init() {
|
await super.init();
|
}
|
|
/**
|
* 支付成功
|
* @param orderNum 订单号
|
* @param payType 支付方式 0-待支付 1-微信 2-支付宝 3-碳积分
|
*/
|
async paySuccess(orderNum: string, payType: number) {
|
const order = await this.orderInfoService.getByOrderNum(orderNum);
|
if (order && order.status == 0) {
|
await this.orderInfoEntity.update(order.id, {
|
payType,
|
status: 1,
|
payTime: new Date(),
|
});
|
// 发送自动确认收货队列
|
const orderConfirm = await this.baseSysParamService.dataByKey(
|
'orderConfirm'
|
);
|
this.orderQueue.add(
|
{ orderId: order.id, action: Action.CONFIRM },
|
{
|
// 自动确认收货时间
|
delay: orderConfirm * 60 * 60 * 1000,
|
}
|
);
|
}
|
return 'success';
|
}
|
|
/**
|
* 微信小程序支付
|
* @param userId
|
* @param orderId
|
*/
|
async wxMiniPay(orderId: number, userId: string) {
|
await this.orderInfoEntity.update(orderId, { wxType: 0 });
|
return await this.wxJSAPI(orderId, userId, 0);
|
}
|
|
/**
|
* 微信公众号支付
|
* @param userId
|
* @param orderId
|
*/
|
async wxMpPay(orderId: number, userId: string) {
|
await this.orderInfoEntity.update(orderId, { wxType: 1 });
|
return await this.wxJSAPI(orderId, userId, 1);
|
}
|
|
/**
|
* 获得appid
|
* @param type 0-小程序 1-公众号 2-App
|
*/
|
async getAppidByType(type: number) {
|
let account;
|
const plugin: any = await this.pluginService.getInstance('wx');
|
// 小程序
|
if (type == 0) {
|
account = (await plugin.MiniApp()).getAccount();
|
}
|
// 公众号
|
if (type == 1) {
|
account = (await plugin.OfficialAccount()).getAccount();
|
}
|
// App
|
if (type == 2) {
|
account = (await plugin.OpenPlatform()).getAccount();
|
}
|
// 获得appid
|
const appid = account.getAppId();
|
return appid;
|
}
|
|
/**
|
* 获得微信支付 SDK 实例
|
* @param type 0-小程序 1-公众号 2-App
|
* @returns
|
*/
|
async wxPayInstance(appid: string) {
|
// 获得插件实例
|
const plugin: any = await this.pluginService.getInstance('pay-wx');
|
// 获得插件配置
|
const config = await plugin.getConfig();
|
// 获得微信支付 SDK 实例
|
const instance = await plugin.getInstance({
|
...config,
|
appid,
|
});
|
return { config, instance };
|
}
|
|
/**
|
* 微信APP支付
|
* @param orderId
|
* @param userId
|
* @returns
|
*/
|
async wxAppPay(orderId: number, userId: string) {
|
const appid = await this.getAppidByType(2);
|
|
const { config, instance } = await this.wxPayInstance(appid);
|
|
const order = await this.getOrder(orderId, userId);
|
const params = {
|
description: '商品采购',
|
out_trade_no: order?.orderNum,
|
notify_url: config.notify_url,
|
amount: {
|
total: new BigNumber(order.price)
|
.minus(order.discountPrice || 0)
|
.multipliedBy(100)
|
.toNumber(),
|
},
|
};
|
|
const result = await instance.transactions_app(params);
|
return result;
|
}
|
|
/**
|
* 获得订单
|
* @param orderId
|
* @param userId
|
* @returns
|
*/
|
async getOrder(orderId: number, userId: string) {
|
const order: OrderInfoEntity = await this.orderInfoService.info(orderId);
|
if (!order || order.status != 0 || order.userId != userId) {
|
throw new CoolCommException('订单不存在或不是可以支付的状态');
|
}
|
return order;
|
}
|
|
/**
|
* 微信JSAPI
|
* @param orderId
|
* @param userId
|
* @param type 0-小程序 1-公众号 2-App
|
* @returns
|
*/
|
async wxJSAPI(orderId: number, userId: string, type = 0) {
|
const order = await this.getOrder(orderId, userId);
|
const openid = await this.userWxService.getOpenid(userId, type);
|
|
const appid = await this.getAppidByType(type);
|
|
const { config, instance } = await this.wxPayInstance(appid);
|
|
const params = {
|
description: '商品采购',
|
out_trade_no: order.orderNum,
|
notify_url: config.notify_url,
|
amount: {
|
total: new BigNumber(order.price)
|
.minus(order.discountPrice || 0)
|
.multipliedBy(100)
|
.toNumber(),
|
},
|
payer: {
|
openid,
|
},
|
scene_info: {
|
payer_client_ip: '127.0.0.1',
|
},
|
};
|
const result = await instance.transactions_jsapi(params);
|
return result;
|
}
|
|
/**
|
* 微信退款
|
* @param order
|
* @param amount
|
* @returns
|
*/
|
async wxRefund(order: OrderInfoEntity, amount: number) {
|
const appid = await this.getAppidByType(order.wxType);
|
const { config, instance } = await this.wxPayInstance(appid);
|
const params = {
|
out_trade_no: order.orderNum,
|
out_refund_no: order.refund.orderNum,
|
notify_url: config.notify_url,
|
amount: {
|
refund: new BigNumber(amount).multipliedBy(100).toNumber(),
|
total: new BigNumber(order.price).multipliedBy(100).toNumber(),
|
currency: 'CNY',
|
},
|
};
|
const result = await instance.refunds(params);
|
if (
|
result.status == 200 ||
|
result.status == 'SUCCESS' ||
|
result.status == 'PROCESSING'
|
) {
|
return true;
|
}
|
throw new CoolCommException(result.message);
|
}
|
|
/**
|
* 读取碳积分兑换比例,默认 100
|
*/
|
async getCarbonRatio() {
|
try {
|
const value = await this.baseSysParamService.dataByKey('carbonratio');
|
const ratio = Number(value);
|
if (ratio > 0) {
|
return ratio;
|
}
|
} catch (e) {}
|
return 100;
|
}
|
|
/**
|
* 碳积分支付:不调用外部渠道
|
* 扣减积分 = 订单实付金额 * carbonratio
|
*/
|
@CoolTransaction()
|
async carbonPay(orderId: number, userId: string, queryRunner?: QueryRunner) {
|
if (!queryRunner) {
|
throw new CoolCommException('事务启动失败');
|
}
|
|
const manager = queryRunner.manager;
|
const order = await manager.findOne(OrderInfoEntity, {
|
where: { id: orderId },
|
});
|
if (!order || order.status != 0 || order.userId != userId) {
|
throw new CoolCommException('订单不存在或不是可以支付的状态');
|
}
|
|
const user = await manager.findOne(UserInfoEntity, {
|
where: { unionid: userId },
|
});
|
if (!user) {
|
throw new CoolCommException('用户不存在');
|
}
|
|
const ratio = await this.getCarbonRatio();
|
const payAmount = new BigNumber(order.price).minus(order.discountPrice || 0);
|
const carbonCost = payAmount.multipliedBy(ratio).toNumber();
|
|
if (Number(user.carbonBalance || 0) < carbonCost) {
|
throw new CoolCommException('碳积分不足');
|
}
|
|
const dec = await manager
|
.createQueryBuilder()
|
.update(UserInfoEntity)
|
.set({ carbonBalance: () => `carbonBalance - ${carbonCost}` })
|
.where('id = :id AND carbonBalance >= :cost', {
|
id: userId,
|
cost: carbonCost,
|
})
|
.execute();
|
if (!dec.affected) {
|
throw new CoolCommException('碳积分不足');
|
}
|
|
await manager.update(OrderInfoEntity, order.id, {
|
payType: 3,
|
status: 1,
|
payTime: new Date(),
|
});
|
|
await manager.save(RecycleTransactionEntity, {
|
userId: user.unionid || String(userId),
|
departmentId: user.departmentId,
|
type: '支出',
|
amount: carbonCost,
|
sourceType: '商城',
|
remark: `商城订单 ${order.orderNum} 碳积分支付`,
|
orderId: order.orderNum,
|
});
|
|
const orderConfirm = await this.baseSysParamService.dataByKey('orderConfirm');
|
this.orderQueue.add(
|
{ orderId: order.id, action: Action.CONFIRM },
|
{
|
delay: orderConfirm * 60 * 60 * 1000,
|
}
|
);
|
|
return true;
|
}
|
}
|