Commit 6d158d61 by 徐康

Merge remote-tracking branch 'origin/qa' into qa

parents 57ffbb8c 2870fd07
package cn.freemud.adapter;
import cn.freemud.base.entity.BaseResponse;
import cn.freemud.constant.CommonsConstant;
import cn.freemud.entities.dto.pay.InvoiceCreateRequest;
import cn.freemud.entities.dto.pay.InvoiceProductDetailRequest;
import cn.freemud.entities.dto.pay.OrderInvoiceRequest;
import cn.freemud.entities.vo.order.CreateOrderInvoiceRequest;
import cn.freemud.enums.InvoiceTypeCodeEnum;
import cn.freemud.enums.ResponseResult;
import cn.freemud.utils.ResponseUtil;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.enums.NewOrderStatus;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class OrderInvoiceAdapter {
// 开票参数
public static final String INVOICE_PRODUCTCODE = "3070401000000000000";
public static final String INVOICE_PRODUCTNAME = "餐饮类商品";
public static final String INVOICE_TAXRATE = "0.06";
// 单张发票订单数量限制
public static final Integer ORDER_INVOICE_NUM_LIMIT = 30;
// 可开发票订单状态
public static final List<Integer> canOpenOrderInvoiceStatus = Arrays.asList(
NewOrderStatus.COMPLETE.getIndex()
);
/**
* 校验订单开票数据
* @return
*/
public static BaseResponse checkOrderOpenInvoiceData(List<OrderBeanV1> orders, CreateOrderInvoiceRequest request){
// 【1】 前端传的订单有误,部分订单查不到详情
if(orders.size() != request.getOrderCodes().size()){
return ResponseUtil.error(ResponseResult.ORDER_QUERY_ANY_ERR);
}
// 【2】 单张发票包含的订单数量限制30
if(orders.size() > ORDER_INVOICE_NUM_LIMIT){
return ResponseUtil.error(ResponseResult.ORDER_INVOINVE_LIMIT_30);
}
Long totalActualPayAmount = orders.stream()
.filter(x->canOpenOrderInvoiceStatus.contains(x.getStatus()))
.filter(x -> x.getActualPayAmount() != null)
.map(e -> e.getActualPayAmount()).reduce(Long::sum).get();
// 【3】 实际支付金额为0,不能开票
if(null == totalActualPayAmount || totalActualPayAmount == 0 ){
return ResponseUtil.error(ResponseResult.ACTUALPAYAMOUNT_IS_ZERO);
}
// 【4】 将前端传的实际支付金额和服务端查出订单【可开票状态】实际支付金额对比,如果不相等,不予开票
if(totalActualPayAmount != request.getTotalActualPayAmount()){
return ResponseUtil.error(ResponseResult.ACTUALPAYAMOUNT_IS_ERROR);
}
// 【5】 单张发票最大限制1000元,超过最大限额不能开票
double actualPayAmount2yuan = new BigDecimal(totalActualPayAmount)
.divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
if(actualPayAmount2yuan > CommonsConstant.CONSTANTS_ONE_THOUSAND){
return ResponseUtil.error(ResponseResult.ACTUALPAYAMOUNT_OUT_OF_ONE_THOUSAND);
}
// 【6】 单张发票金额最小限制???元,低于最小限制不能开票
return ResponseUtil.success();
}
public static InvoiceCreateRequest convert2InvoiceCreateRequest(List<OrderBeanV1> orders, CreateOrderInvoiceRequest createRequest){
InvoiceCreateRequest request = new InvoiceCreateRequest();
request.setPartnerId(createRequest.getPartnerId());
request.setInvoiceTerminalCode(CommonsConstant.CONSTANTS_TWO_STRING);
request.setOrgCode(null);
request.setPushChannelType(CommonsConstant.CONSTANTS_ZERO_INTEGER);
request.setInvoiceTypeCode(InvoiceTypeCodeEnum.ELECTRONIC_INVOICE.getFmType());
request.setInvoiceNo(UUID.randomUUID().toString().replaceAll("-", ""));
request.setDrawer(createRequest.getDrawer());
// 订单商品明细
List<InvoiceProductDetailRequest> productDetailList = new ArrayList<>();
// 支付总金额
BigDecimal actualPayAmount = new BigDecimal(0);
for(OrderBeanV1 orderBean : orders){
actualPayAmount = new BigDecimal(orderBean.getActualPayAmount()).add(actualPayAmount);
}
// 分转元
BigDecimal actualPayAmount2yuan = actualPayAmount.divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
InvoiceProductDetailRequest invoiceDetailRequest = new InvoiceProductDetailRequest();
invoiceDetailRequest.setProductCode(INVOICE_PRODUCTCODE);
invoiceDetailRequest.setProductName(INVOICE_PRODUCTNAME);
invoiceDetailRequest.setProductSpecification("");
invoiceDetailRequest.setGoodsUnit("");
invoiceDetailRequest.setGoodsQuantity(CommonsConstant.CONSTANTS_ONE_INTEGER);
invoiceDetailRequest.setGoodsPrice(actualPayAmount2yuan);
invoiceDetailRequest.setGoodsTotalPrice(actualPayAmount2yuan);
invoiceDetailRequest.setGoodsTaxRate(new BigDecimal(INVOICE_TAXRATE).setScale(2, BigDecimal.ROUND_HALF_UP));
BigDecimal goodsTotalTax = invoiceDetailRequest.getGoodsTotalPrice()
.multiply(invoiceDetailRequest.getGoodsTaxRate()).setScale(2, BigDecimal.ROUND_HALF_UP);
invoiceDetailRequest.setGoodsTotalTax(goodsTotalTax);
productDetailList.add(invoiceDetailRequest);
request.setProductDetailList(productDetailList);
return request;
}
public static OrderInvoiceRequest convert2OrderInvoiceRequest(InvoiceCreateRequest invoiceCreateRequest
, List<String> orderCodes, String scanUrl, String memberId){
OrderInvoiceRequest request = new OrderInvoiceRequest();
request.setPartnerId(invoiceCreateRequest.getPartnerId());
request.setInvoiceType(CommonsConstant.CONSTANTS_TWO_INTEGER);
request.setContent("test"); // todo
request.setAmount(invoiceCreateRequest.getProductDetailList().get(0).getGoodsTotalPrice().multiply(new BigDecimal(100)).intValue());
request.setInvoiceUrl(scanUrl);
request.setUserId(memberId);
request.setInvoiceNo(invoiceCreateRequest.getInvoiceNo());
request.setOrderCodes(orderCodes);
return request;
}
}
......@@ -19,5 +19,17 @@ public class CommonsConstant {
public static final String ORDER_COMPLAIN_CLOSE = "close";
public static final String one_thousand = "close";
public static final int CONSTANTS_ONE_THOUSAND = 1000;
public static final Integer CONSTANTS_ZERO_INTEGER = 0;
public static final Integer CONSTANTS_ONE_INTEGER = 1;
public static final String CONSTANTS_TWO_STRING = "2";
public static final Integer CONSTANTS_TWO_INTEGER = 2;
}
\ No newline at end of file
package cn.freemud.entities.dto.order;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
public class InvoiceCreateResponse {
@ApiModelProperty(value = "扫码开票url地址")
private String scanUrl;
@ApiModelProperty(value = "发票id")
private String invoiceId;
@ApiModelProperty(value = "提取码")
private String code;
@ApiModelProperty(value = "扫码开票截至时间")
private Date endingDate;
}
package cn.freemud.entities.dto.pay;
import cn.freemud.enums.InvoiceTypeCodeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.List;
@Data
public class InvoiceCreateRequest {
@ApiModelProperty(value = "商户编号")
private String partnerId;
@ApiModelProperty(value = "开票终端代码,1纸票,2电票")
private String invoiceTerminalCode;
@ApiModelProperty(value = "机构代码,如果为空则上传至税号对应的机构下,如果维护了机构则按照机构归属待开信息")
private String orgCode;
@ApiModelProperty(value = "推送渠道标识,0为微信扫码url,默认为null")
private Integer pushChannelType;
/**
* @see InvoiceTypeCodeEnum
*/
@ApiModelProperty(value = "发票类型,1:增值税专用发票;2:增值税普通发票;3:增值税电子发票;4:增值税卷式发票;5:增值税专用电子发票")
@NotEmpty(message = "发票类型不能为空")
private String invoiceTypeCode;
@ApiModelProperty(value = "开票流水号")
@NotEmpty(message = "开票流水号不能为空")
private String invoiceNo;
@ApiModelProperty(value = "开票人")
@NotEmpty(message = "开票人不能为空")
private String drawer;
@ApiModelProperty(value = "发票明细")
private List<InvoiceProductDetailRequest> productDetailList;
}
package cn.freemud.entities.dto.pay;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.math.BigDecimal;
@Data
public class InvoiceProductDetailRequest {
@ApiModelProperty(value = "税收分类编码")
@NotEmpty(message = "税收分类编码不能为空")
private String productCode;
@ApiModelProperty(value = "商品名称")
@NotEmpty(message = "商品名称不能为空")
private String productName;
@ApiModelProperty(value = "规格型号")
private String productSpecification;
@ApiModelProperty(value = "计量单位")
private String goodsUnit;
@ApiModelProperty(value = "商品数量")
private Integer goodsQuantity;
@ApiModelProperty(value = "商品单价")
private BigDecimal goodsPrice;
@ApiModelProperty(value = "商品总价,保留两位小数")
@NotEmpty(message = "商品总价不能为空")
private BigDecimal goodsTotalPrice;
@ApiModelProperty(value = "税额,保留两位小数")
private BigDecimal goodsTotalTax;
@ApiModelProperty(value = "税率")
@NotEmpty(message = "税率不能为空")
private BigDecimal goodsTaxRate;
}
package cn.freemud.entities.dto.pay;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
public class OrderInvoiceRequest {
@ApiModelProperty("商户号")
@NotEmpty(message = "商户号不能为空")
private String partnerId;
@ApiModelProperty("发票类型 1:普通发票 2:增值发票")
@NotNull(message = "发票类型不能为空")
private Integer invoiceType;
@ApiModelProperty("发票抬头")
private String title;
@ApiModelProperty("发票内容")
@NotBlank(message = "发票内容不能为空")
private String content;
@ApiModelProperty("税号")
private String taxNo;
@ApiModelProperty("发票金额 单位分")
@NotNull(message = "发票金额不能为空")
private Integer amount;
@ApiModelProperty("发票地址")
private String address;
@ApiModelProperty("电话号码")
private String phoneNo;
@ApiModelProperty("银行账号")
private String bankCardNo;
@ApiModelProperty("开户行")
private String invoiceBank;
@ApiModelProperty("发票URL地址")
@NotBlank(message = "发票URL地址不能为空")
private String invoiceUrl;
@ApiModelProperty("用户Id")
@NotBlank(message = "用户Id不能为空")
private String userId;
@ApiModelProperty("开票流水号")
@NotBlank(message = "开票流水号不能为空")
private String invoiceNo;
@ApiModelProperty("关联订单号")
@NotNull(message = "关联订单号不能为空")
private List<String> orderCodes;
}
......@@ -5,6 +5,7 @@ import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
......@@ -21,5 +22,14 @@ public class CreateOrderInvoiceRequest {
@ApiModelProperty("订单编号")
@NotNull(message = "订单编号不能为空")
@Size(max = 30,message = "单张发票限制30个订单,超过限额不能开票")
private List<String> orderCodes;
@ApiModelProperty(value = "开票人")
@NotEmpty(message = "开票人不能为空")
private String drawer;
@ApiModelProperty(value = "开票金额,单位:分")
@NotNull(message = "开票金额不能为空")
private Long totalActualPayAmount;
}
package cn.freemud.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum InvoiceTypeCodeEnum {
SPECIAL_INVOICE("1", "004", "增值税专用发票"),
COMMON_INVOICE("2", "007", "增值税普通发票"),
ELECTRONIC_INVOICE("3", "026", "增值税电子发票"),
ROLL_INVOICE("4", "025", "增值税卷式发票"),
SPECIAL_ELECTRONIC_INVOICE("5", "028", "增值税专用电子发票"),
;
/**
* 非码类型
*/
private String fmType;
/**
* 百望类型
*/
private String bwType;
private String desc;
}
......@@ -179,6 +179,12 @@ public enum ResponseResult {
STORE_NO_OPEN("45072", "选择时间不在门店营业时间范围内",""),
STORE_SELF_ERROR_10("45073", "请在营业结束时间前10分钟下单",""),
ORDER_APPEAL_ERR("45074", "申诉失败",""),
ORDER_QUERY_ERR("45075", "订单查询失败",""),
ACTUALPAYAMOUNT_IS_ZERO("45076", "实际支付金额为0,不能开票",""),
ACTUALPAYAMOUNT_OUT_OF_ONE_THOUSAND("45077", "单张发票最大限制1000元,超过最大限额不能开票",""),
ORDER_INVOINVE_LIMIT_30("45078", "单张发票限制30个订单,超过限额不能开票",""),
ACTUALPAYAMOUNT_IS_ERROR("45079", "实际支付金额有误,不予开票",""),
ORDER_QUERY_ANY_ERR("45080", "部分订单查询失败",""),
/**
* 售后单
......
......@@ -334,6 +334,9 @@ public class OrderServiceImpl implements Orderservice {
@Autowired
private OrderManager orderManager;
@Autowired
private OrderServiceClient orderServiceClient;
@Override
public BaseResponse checkBeforeCreateOrder(CheckBeforeCreateOrderRequestVo requestVo) {
......@@ -4386,12 +4389,41 @@ public class OrderServiceImpl implements Orderservice {
@Override
public BaseResponse createAndGetOrderInvoice(CreateOrderInvoiceRequest request){
// 1. 【查询订单详情】
QueryOrdersResponse orderList = this.getOrderList(request.getOrderCodes());
AssortmentCustomerInfoVo userLoginInfoDto = customerInfoManager.getCustomerInfoByObject(request.getSessionId());
if (userLoginInfoDto == null || StringUtils.isEmpty(userLoginInfoDto.getMemberId())) {
return ResponseUtil.error(ResponseResult.NOT_LOGIN);
}
// 【1】. 查询订单详情
QueryOrdersResponse orderResponse = this.getOrderList(request.getOrderCodes());
if(!Objects.equals(ResponseCodeConstant.RESPONSE_SUCCESS, orderResponse.getErrcode())){
return ResponseUtil.error(orderResponse.getErrcode()+"", orderResponse.getErrmsg());
}
QueryOrdersResponse.DataBean dataBean = orderResponse.getData();
if(null == dataBean || CollectionUtils.isEmpty(dataBean.getOrders())){
return ResponseUtil.error(ResponseResult.ORDER_QUERY_ERR);
}
// 【2】. 【校验订单开票数据】
BaseResponse checkResponse = OrderInvoiceAdapter.checkOrderOpenInvoiceData(dataBean.getOrders(), request);
if (!Objects.equals(ResponseCodeConstant.RESPONSE_SUCCESS_STR, checkResponse.getCode())) {
return checkResponse;
}
// 2. 【调用三方百望接口开订单发票】
// 【3】. 【调用支付接口开订单发票,非码支付系统内部再调用三方-百望系统开票】
InvoiceCreateRequest invoiceCreateRequest = OrderInvoiceAdapter.convert2InvoiceCreateRequest(dataBean.getOrders(), request);
com.freemud.application.sdk.api.base.BaseResponse<InvoiceCreateResponse> invoiceResponse = paymentNewClient.createInvoice(invoiceCreateRequest);
if (!Objects.equals(ResponseCodeConstant.RESPONSE_SUCCESS_STR, invoiceResponse.getCode()) || null == invoiceResponse.getData()) {
return ResponseUtil.error(invoiceResponse.getCode(), invoiceResponse.getMessage());
}
// 3. 【录入发票记录,修改订单发票状态】
// 【4】. 【录入发票记录,修改订单发票状态】
OrderInvoiceRequest orderInvoiceRequest = OrderInvoiceAdapter.convert2OrderInvoiceRequest(invoiceCreateRequest, request.getOrderCodes()
, invoiceResponse.getData().getScanUrl() , userLoginInfoDto.getMemberId());
BaseResponse orderInvoiceResponse = orderServiceClient.createInvoice(orderInvoiceRequest);
if (!Objects.equals(ResponseCodeConstant.RESPONSE_SUCCESS_STR, orderInvoiceResponse.getCode())) {
return orderInvoiceResponse;
}
return ResponseUtil.success();
}
......
package cn.freemud.service.thirdparty;
import cn.freemud.annotations.LogIgnoreFeign;
import cn.freemud.base.entity.BaseResponse;
import cn.freemud.entities.dto.pay.OrderInvoiceRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(name = "order-service",url = "${order.service.url:}")
@RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public interface OrderServiceClient {
/**
* 创建订单开票记录
*/
@LogIgnoreFeign(logMessage="createInvoice")
@PostMapping("/order/v2/invoice/create")
BaseResponse createInvoice(@RequestBody OrderInvoiceRequest orderCounts);
}
......@@ -4,6 +4,8 @@ import cn.freemud.annotations.LogIgnoreFeign;
import cn.freemud.constant.ResponseCodeKeyConstant;
import cn.freemud.entities.dto.order.FacePayRequestDto;
import cn.freemud.entities.dto.order.FacePayResponseDto;
import cn.freemud.entities.dto.order.InvoiceCreateResponse;
import cn.freemud.entities.dto.pay.InvoiceCreateRequest;
import cn.freemud.entities.dto.pay.UnifiedOrderRequestDto;
import cn.freemud.entities.dto.order.RefundQueryResponseDto;
import org.springframework.cloud.openfeign.FeignClient;
......@@ -48,4 +50,12 @@ public interface PaymentNewClient {
@PostMapping("paymentcenter/refundQuery")
com.freemud.application.sdk.api.base.BaseResponse<RefundQueryResponseDto> refundQuery(@RequestBody FacePayRequestDto orderPayDto);
/**
* 开订单发票
*/
@LogIgnoreFeign(logMessage="paymentcenter/invoice/create",statusCodeFieldName= ResponseCodeKeyConstant.STATUS_CODE)
@PostMapping("paymentcenter/invoice/create")
com.freemud.application.sdk.api.base.BaseResponse<InvoiceCreateResponse> createInvoice(@RequestBody InvoiceCreateRequest request);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment