Quellcode durchsuchen

Merge branch 'feature/push_invoice' into dev

# Conflicts:
#	sp-admin/sa-view/tb-fee-statistics/tb-fee-details-list.html
#	sp-admin/sa-view/tb-invoice-info/tb-invoice-info-list.html
#	sp-admin/sa-view/tb-invoice-order/tb-invoice-order-add.html
#	sp-admin/sa-view/tb-invoice-order/tb-invoice-order-list.html
#	sp-server/src/main/java/com/pj/project/tb_business/TbBusinessService.java
#	sp-server/src/main/java/com/pj/project/tb_fee_details/TbFeeDetailsService.java
#	sp-server/src/main/java/com/pj/project/tb_invoice_order/TbInvoiceOrder.java
#	sp-server/src/main/java/com/pj/project/tb_invoice_order/TbInvoiceOrderService.java
qzyReal vor 3 Jahren
Ursprung
Commit
cdac470ca7
30 geänderte Dateien mit 2922 neuen und 938 gelöschten Zeilen
  1. 411 416
      sp-admin/sa-view/tb-fee-statistics/tb-fee-details-list.html
  2. 219 0
      sp-admin/sa-view/tb-invoice-info/online-invioce.html
  3. 14 10
      sp-admin/sa-view/tb-invoice-info/tb-invoice-info-list.html
  4. 123 127
      sp-admin/sa-view/tb-invoice-order/tb-invoice-order-add.html
  5. 258 268
      sp-admin/sa-view/tb-invoice-order/tb-invoice-order-list.html
  6. 222 0
      sp-server/src/main/java/com/pj/api/invoice/CallDomo.java
  7. 54 0
      sp-server/src/main/java/com/pj/api/invoice/api/InvoiceApplyController.java
  8. 29 0
      sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApply.java
  9. 26 0
      sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApplyCallBack.java
  10. 110 0
      sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApplyCallBackSub.java
  11. 101 0
      sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApplySub.java
  12. 68 0
      sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApplySubDetail.java
  13. 60 0
      sp-server/src/main/java/com/pj/api/invoice/bo/invoiceDetail.java
  14. 22 0
      sp-server/src/main/java/com/pj/api/invoice/bo/testbb.java
  15. 20 0
      sp-server/src/main/java/com/pj/api/invoice/demo.java
  16. 260 0
      sp-server/src/main/java/com/pj/api/invoice/service/InvoiceApplyService.java
  17. 181 0
      sp-server/src/main/java/com/pj/api/invoice/utils/InvoiceUtils.java
  18. 52 0
      sp-server/src/main/java/com/pj/current/config/InvoiceConfig.java
  19. 1 1
      sp-server/src/main/java/com/pj/project/tb_business/TbBusinessService.java
  20. 10 10
      sp-server/src/main/java/com/pj/project/tb_fee_details/TbFeeDetailsService.java
  21. 93 0
      sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetails.java
  22. 121 0
      sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetailsController.java
  23. 56 0
      sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetailsMapper.java
  24. 80 0
      sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetailsMapper.xml
  25. 172 0
      sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetailsService.java
  26. 10 0
      sp-server/src/main/java/com/pj/project/tb_invoice_info/TbInvoiceInfo.java
  27. 8 6
      sp-server/src/main/java/com/pj/project/tb_invoice_info/TbInvoiceInfoService.java
  28. 82 72
      sp-server/src/main/java/com/pj/project/tb_invoice_order/TbInvoiceOrder.java
  29. 47 28
      sp-server/src/main/java/com/pj/project/tb_invoice_order/TbInvoiceOrderService.java
  30. 12 0
      sp-server/src/main/resources/application-dev.yml

+ 411 - 416
sp-admin/sa-view/tb-fee-statistics/tb-fee-details-list.html

@@ -96,245 +96,240 @@
             </div>
 
 
-            <el-button type="primary" icon="el-icon-search" @click="p.pageNo = 1; f5()">查询</el-button>
-            <br/>
-        </el-form>
-        <!-- ------------- 快捷按钮 ------------- -->
-        <div class="fast-btn">
-            <el-button type="info" @click="sa.f5()">刷新</el-button>
-            <el-button type="warning" @click="exportFn()">导出</el-button>
-            <el-button class="c-btn" type="success" icon="el-icon" @click="print()">打印</el-button>
-            <slot></slot>
-        </div>
-        <div class="fast-btn">
-            <el-button class="c-btn" type="success" icon="el-icon" v-if="sa.isAuth('tb-kaidan-confirm')"
-                       @click="kaiDanConfirm()">开单确认
-            </el-button>
-            <el-button class="c-btn" type="success" icon="el-icon" v-if="sa.isAuth('tb-diaodu-confirm')"
-                       @click="diaoDuConfirm()">复核确认
-            </el-button>
-            <el-button class="c-btn" type="success" icon="el-icon" v-if="sa.isAuth('tb-jicha-confirm')"
-                       @click="jiChaConfirm()">稽查确认
-            </el-button>
-            <el-button class="c-btn" type="danger" icon="el-icon" v-if="sa.isAuth('tb-jicha-cancel')"
-                       @click="jiChaCancel()">取消确认
-            </el-button>
-            <slot></slot>
-            <div class="price-t">
-                总共<span style="color: #ff6600">&nbsp&nbsp{{dataCount}}&nbsp&nbsp</span>条&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
-                总金额<span style="color: #ff6600">&nbsp&nbsp{{totalPrice}}&nbsp&nbsp</span>元
-            </div>
-        </div>
-        <!-- ------------- 数据列表 ------------- -->
-        <el-table class="data-table" ref="data-table" :data="dataList" show-summary :summary-method="getSumRol">
-            <sa-td type="selection"></sa-td>
-            <!--					<sa-td name="作业类型" prop="feeType" type="enum"-->
-            <!--						   :jv="{1: '核酸检测',2: '消杀作业', 3: '装卸作业', 4: '停车费', 5: '过磅费', 6: '入场管理费', 7: '充电打冷作业'}"></sa-td>-->
-            <sa-td name="收费项目" prop="feeType" type="enum"
-                   :jv="{1: '核酸检测',2: '消杀作业', 3: '装卸作业', 4: '停车费', 5: '过磅费', 6: '入场管理费', 7: '充电打冷作业'}"></sa-td>
-            <sa-td name="业务类型" prop="itemTypeName"></sa-td>
-            <sa-td name="车型" prop="itemName"></sa-td>
-            <sa-td name="车牌号" prop="carNo" width="90px"></sa-td>
-            <sa-td name="重量(kg)" prop="weight"></sa-td>
-            <sa-td name="数量" prop="num"></sa-td>
-            <sa-td name="单价(元)" prop="unitPrice"></sa-td>
-            <sa-td name="总价(元)" prop="itemPrice"></sa-td>
-            <sa-td name="结算状态" prop="isSettle" type="enum" :jv="{0: '未结算',1: '已结算'}"></sa-td>
-            <sa-td name="复核状态" prop=""></sa-td>
-            <!--					<sa-td name="税率(%)" prop="taxRate" ></sa-td>-->
-            <el-table-column label="税率(%)">
-
-            </el-table-column>
-            <!--					<sa-td name="税款(元)" prop="taxPrice" ></sa-td>-->
-            <el-table-column label="税款(元)">
-                <template slot-scope="s">
-                    <span>{{Number(s.row.taxPrice).toFixed(2)}}</span>
-                </template>
-            </el-table-column>
-            <!--					<sa-td name="不含税金额(元)" prop="noTaxPrice" ></sa-td>-->
-            <el-table-column label="不含税金额(元)">
-                <template slot-scope="s">
-                    <span>{{Number(s.row.noTaxPrice).toFixed(2)}}</span>
-                </template>
-            </el-table-column>
-            <!-- 	<sa-td name="收款方式" prop="payType" type="enum" :jv="{3: '微信支付'}"></sa-td>
-                <sa-td name="收款种类" prop="payMode" type="enum" :jv="{1: '直接收款'}"></sa-td> -->
-            <el-table-column label="业务单号" width="140px">
-                <template slot-scope="s">
-                    <span v-if="s.row.businessNo != null && s.row.businessNo != ''">{{s.row.businessNo}}</span>
-                    <span v-else>{{s.row.businessCarNo}}</span>
-                </template>
-            </el-table-column>
-            <!--					<sa-td name="订单编号" prop="transactionId" width="220px" ></sa-td>-->
-            <el-table-column label="微信支付业务单号" width="220px">
-                <template slot-scope="s">
-                    <el-tooltip :content="s.row.transactionId" placement="bottom" effect="light">
-                        <el-button class="keyButton">{{ s.row.transactionId }}</el-button>
-                    </el-tooltip>
-                </template>
-            </el-table-column>
-            <sa-td name="作业编号" prop="businessItemNo" width="145px"></sa-td>
-            <sa-td name="作业公司" prop="pickCustomerName"></sa-td>
-            <sa-td name="客户名称" prop="customerName"></sa-td>
-            <sa-td name="发票号" prop="invoice" width="145px"></sa-td>
-            <sa-td name="主体名称" prop="entityName"></sa-td>
-            <sa-td name="生成时间" prop="createTime" width="150px"></sa-td>
-            <sa-td name="付款时间" prop="payTime" width="150px"></sa-td>
-            <sa-td name="备注" prop="remark"></sa-td>
-            <sa-td name="开单员" prop="kaiDanPerson" width="80px"></sa-td>
-            <sa-td name="复核员" prop="diaoDuPerson" width="80px"></sa-td>
-            <sa-td name="统计稽查员" prop="jiChaPerson" width="80px"></sa-td>
+					<el-button type="primary" icon="el-icon-search" @click="p.pageNo = 1; f5()">查询</el-button>
+					<br />
+				</el-form>
+				<!-- ------------- 快捷按钮 ------------- -->
+				<div class="fast-btn">
+					<el-button type="info"    @click="sa.f5()">刷新</el-button>
+					<el-button type="warning"  @click="exportFn()">导出</el-button>
+					<el-button class="c-btn" type="success" icon="el-icon" @click="print()">打印</el-button>
+					<slot></slot>
+				</div>
+				<div class="fast-btn">
+					<el-button class="c-btn" type="success" icon="el-icon" v-if="sa.isAuth('tb-kaidan-confirm')" @click="kaiDanConfirm()">开单确认</el-button>
+					<el-button class="c-btn" type="success" icon="el-icon" v-if="sa.isAuth('tb-diaodu-confirm')" @click="diaoDuConfirm()">复核确认</el-button>
+					<el-button class="c-btn" type="success" icon="el-icon" v-if="sa.isAuth('tb-jicha-confirm')" @click="jiChaConfirm()">稽查确认</el-button>
+					<el-button class="c-btn" type="danger" icon="el-icon" v-if="sa.isAuth('tb-jicha-cancel')" @click="jiChaCancel()">取消确认</el-button>
+					<slot></slot>
+					<div class="price-t">
+						总共<span style="color: #ff6600">&nbsp&nbsp{{dataCount}}&nbsp&nbsp</span>条&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
+						总金额<span style="color: #ff6600">&nbsp&nbsp{{totalPrice}}&nbsp&nbsp</span>元
+					</div>
+				</div>
+				<!-- ------------- 数据列表 ------------- -->
+				<el-table class="data-table" ref="data-table" :data="dataList" show-summary :summary-method="getSumRol">
+					<sa-td type="selection"></sa-td>
+<!--					<sa-td name="作业类型" prop="feeType" type="enum"-->
+<!--						   :jv="{1: '核酸检测',2: '消杀作业', 3: '装卸作业', 4: '停车费', 5: '过磅费', 6: '入场管理费', 7: '充电打冷作业'}"></sa-td>-->
+					<sa-td name="收费项目" prop="feeType" type="enum"
+						   :jv="{1: '核酸检测',2: '消杀作业', 3: '装卸作业', 4: '停车费', 5: '过磅费', 6: '入场管理费', 7: '充电打冷作业'}"></sa-td>
+					<sa-td name="业务类型" prop="itemTypeName" ></sa-td>
+					<sa-td name="车型" prop="itemName" ></sa-td>
+					<sa-td name="车牌号" prop="carNo" width="90px" ></sa-td>
+					<sa-td name="重量(kg)" prop="weight" ></sa-td>
+					<sa-td name="数量" prop="num" ></sa-td>
+					<sa-td name="单价(元)" prop="unitPrice" ></sa-td>
+					<sa-td name="总价(元)" prop="itemPrice" ></sa-td>
+					<sa-td name="结算状态" prop="isSettle" type="enum" :jv="{0: '未结算',1: '已结算'}"></sa-td>
+					<sa-td name="复核状态" prop="" ></sa-td>
+<!--					<sa-td name="税率(%)" prop="taxRate" ></sa-td>-->
+					<el-table-column label="税率(%)" >
+						<template slot-scope="s">
+							<span>{{s.row.taxRate * 100}}</span>
+						</template>
+					</el-table-column>
+<!--					<sa-td name="税款(元)" prop="taxPrice" ></sa-td>-->
+					<el-table-column label="税款(元)" >
+						<template slot-scope="s">
+							<span>{{Number(s.row.taxPrice).toFixed(2)}}</span>
+						</template>
+					</el-table-column>
+<!--					<sa-td name="不含税金额(元)" prop="noTaxPrice" ></sa-td>-->
+					<el-table-column label="不含税金额(元)" >
+						<template slot-scope="s">
+							<span>{{Number(s.row.noTaxPrice).toFixed(2)}}</span>
+						</template>
+					</el-table-column>
+				<!-- 	<sa-td name="收款方式" prop="payType" type="enum" :jv="{3: '微信支付'}"></sa-td>
+					<sa-td name="收款种类" prop="payMode" type="enum" :jv="{1: '直接收款'}"></sa-td> -->
+					<el-table-column label="业务单号" width="140px">
+						<template slot-scope="s">
+							<span v-if="s.row.businessNo != null && s.row.businessNo != ''" >{{s.row.businessNo}}</span>
+							<span v-else>{{s.row.businessCarNo}}</span>
+						</template>
+					</el-table-column>
+<!--					<sa-td name="订单编号" prop="transactionId" width="220px" ></sa-td>-->
+					<el-table-column label="微信支付业务单号" width="220px">
+						<template slot-scope="s">
+							<el-tooltip :content="s.row.transactionId"placement="bottom"effect="light">
+								<el-button class="keyButton">{{ s.row.transactionId }}</el-button>
+							</el-tooltip>
+						</template>
+					</el-table-column>
+					<sa-td name="作业编号" prop="businessItemNo" width="145px" ></sa-td>
+					<sa-td name="作业公司" prop="pickCustomerName" ></sa-td>
+					<sa-td name="客户名称" prop="customerName" ></sa-td>
+					<sa-td name="发票号" prop="invoice" width="145px"></sa-td>
+					<sa-td name="主体名称" prop="entityName" ></sa-td>
+					<sa-td name="生成时间" prop="createTime" width="150px" ></sa-td>
+					<sa-td name="付款时间" prop="payTime"  width="150px" ></sa-td>
+					<sa-td name="更新时间" prop="updateTime"  width="150px" ></sa-td>
+					<sa-td name="备注" prop="remark" ></sa-td>
+					<sa-td name="开单员" prop="kaiDanPerson" width="80px" ></sa-td>
+					<sa-td name="复核员" prop="diaoDuPerson" width="80px" ></sa-td>
+					<sa-td name="统计稽查员" prop="jiChaPerson" width="80px" ></sa-td>
 
-            <!--					<el-table-column label="操作" fixed="right"  width="240px">-->
-            <!--						<template slot-scope="s">-->
-            <!--							<el-button class="c-btn" type="success" icon="el-icon-view" @click="get(s.row)">查看</el-button>-->
-            <!--							<el-button class="c-btn" type="primary" icon="el-icon-edit" @click="update(s.row)">修改</el-button>-->
-            <!--							<el-button class="c-btn" type="danger" icon="el-icon-delete" @click="del(s.row)">删除</el-button>-->
-            <!--						</template>-->
-            <!--					</el-table-column>-->
-        </el-table>
-        <!-- ------------- 分页 ------------- -->
-        <sa-item type="page" :curr.sync="p.pageNo" :size.sync="p.pageSize" :total="dataCount" @change="f5()"></sa-item>
-    </div>
-    <el-dialog title="提示" :visible.sync="emodel.visible" width="38%">
-        <!--				<el-form size="mini">-->
-        <!--					<div class="c-item">-->
-        <!--						<label class="c-label">日期:</label>-->
-        <!--						<el-date-picker type="date" value-format="yyyy-MM-dd" v-model="emodel.form.payDay"></el-date-picker>-->
-        <!--					</div>-->
-        <!--				</el-form>-->
-        <div class="c-item">
-            <label class="c-label">收费项目:</label>
-            <el-select v-model="emodel.form.feeType" placeholder="请选择" filterable>
-                <el-option label="核酸检测" value="1"></el-option>
-                <el-option label="消杀作业" value="2"></el-option>
-                <el-option label="装卸作业" value="3"></el-option>
-                <el-option label="停车费" value="4"></el-option>
-                <el-option label="过磅费" value="5"></el-option>
-                <el-option label="入场管理费" value="6"></el-option>
-                <el-option label="充电打冷作业" value="7"></el-option>
-            </el-select>
-        </div>
-        <div class="c-item">
-            <label class="c-label">业务类型:</label>
-            <el-select v-model="emodel.form.itemTypeName" placeholder="请选择" filterable>
-                <el-option v-for="item in itemTypeList" :key="item.id"
-                           :label="item.name" :value="item.name">
-                </el-option>
-            </el-select>
-        </div>
-        <div class="c-item">
-            <label class="c-label"><span style="color: red;">*</span>日期范围:</label>
-            <el-date-picker size="mini" v-model="exportTime" type="daterange" unlink-panels="false"
-                            range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
-                            format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd">
-            </el-date-picker>
-        </div>
-        <span slot="footer" class="dialog-footer">
+<!--					<el-table-column label="操作" fixed="right"  width="240px">-->
+<!--						<template slot-scope="s">-->
+<!--							<el-button class="c-btn" type="success" icon="el-icon-view" @click="get(s.row)">查看</el-button>-->
+<!--							<el-button class="c-btn" type="primary" icon="el-icon-edit" @click="update(s.row)">修改</el-button>-->
+<!--							<el-button class="c-btn" type="danger" icon="el-icon-delete" @click="del(s.row)">删除</el-button>-->
+<!--						</template>-->
+<!--					</el-table-column>-->
+				</el-table>
+				<!-- ------------- 分页 ------------- -->
+				<sa-item type="page" :curr.sync="p.pageNo" :size.sync="p.pageSize" :total="dataCount" @change="f5()"></sa-item>
+			</div>
+			<el-dialog title="提示" :visible.sync="emodel.visible" width="38%">
+<!--				<el-form size="mini">-->
+<!--					<div class="c-item">-->
+<!--						<label class="c-label">日期:</label>-->
+<!--						<el-date-picker type="date" value-format="yyyy-MM-dd" v-model="emodel.form.payDay"></el-date-picker>-->
+<!--					</div>-->
+<!--				</el-form>-->
+				<div class="c-item">
+					<label class="c-label">收费项目:</label>
+					<el-select v-model="emodel.form.feeType" placeholder="请选择" filterable>
+						<el-option label="核酸检测" value="1"></el-option>
+						<el-option label="消杀作业" value="2"></el-option>
+						<el-option label="装卸作业" value="3"></el-option>
+						<el-option label="停车费" value="4"></el-option>
+						<el-option label="过磅费" value="5"></el-option>
+						<el-option label="入场管理费" value="6"> </el-option>
+						<el-option label="充电打冷作业" value="7"> </el-option>
+					</el-select>
+				</div>
+				<div class="c-item">
+					<label class="c-label">业务类型:</label>
+					<el-select v-model="emodel.form.itemTypeName" placeholder="请选择" filterable>
+						<el-option v-for="item in itemTypeList" :key="item.id"
+								   :label="item.name" :value="item.name">
+						</el-option>
+					</el-select>
+				</div>
+				<div class="c-item">
+					<label class="c-label"><span style="color: red;">*</span>日期范围:</label>
+					<el-date-picker size="mini" v-model="exportTime" type="daterange" unlink-panels="false"
+									range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
+									format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd">
+					</el-date-picker>
+				</div>
+				<span slot="footer" class="dialog-footer">
 					<el-button @click="emodel.visible = false">取 消</el-button>
 					<el-button type="primary" @click="">确 定</el-button>
 				</span>
-    </el-dialog>
-</div>
-<script>
-    var app = new Vue({
-        components: {
-            "sa-item": httpVueLoader('../../sa-frame/com/sa-item.vue'),
-            "sa-td": httpVueLoader('../../sa-frame/com/sa-td.vue'),
-        },
-        el: '.vue-box',
-        data: {
-            p: { // 查询参数
-                id: '',		// 主键
-                businessNo: '',		// 业务单号
-                carNo: '',		// 车牌号
-                feeType: '',		//收费类型
-                itemTypeId: '',		// 业务类型id
-                itemTypeName: '',		// 业务类型
-                itemId: '',		//
-                itemName: '',		// 业务项
-                itemPrice: '',		// 项目金额(元)
-                payDay: '',		// 支付日期
-                payType: '',		// 支付方式(3=微信支付)
-                createTime: '',		// 创建时间
-                pageNo: 1,		// 当前页
-                pageSize: 10,	// 页大小
-                sortType: 11,		// 排序方式
-                type: '',
-                isInvoice: '',   //是否开票
-            },
-            dataCount: 0,
-            dataList: [], // 数据集合
-            itemTypeList: [],
-            selectTime: [],
-            selectTimeRange: {
-                beginTime: '', //查询开始时间
-                endTime: '', //查询结束时间
-            },
-            exportTime: [],
-            emodel: {
-                visible: false,
-                form: {
-                    // payDay: ''
-                    feeType: '',
-                    itemTypeName: '',
-                    beginTime: '', //查询开始时间
-                    endTime: '', //查询结束时间
-                }
-            },
-            totalPrice: 0,
-            tableSum: {
-                itemPriceSum: 0,
-                taxPriceSum: 0,
-                noTaxPriceSum: 0,
-            },
-        },
-        methods: {
-            getSumRol(param) {
-                console.log("执行了getSumRol")
-                const columns = param.columns;
-                const sums = [];
-                columns.forEach((column, index) => {
-                    if (index === 0) {
-                        sums[index] = "合计";
-                        return;
-                    }
-                    //根据当前列绑定的字段名进行判断,根据字段名决定展示什么内容
-                    switch (column.label) {
-                        //金额;
-                        case "总价(元)":
-                            //在这里你就可以根据需要对数据进行一些处理(保留小数位数,加上单位等)
-                            sums[index] = this.tableSum.itemPriceSum;
-                            break;
-                        //人数
-                        case "税款(元)":
-                            sums[index] = this.tableSum.taxPriceSum;
-                            break;
-                        //件数;
-                        case "不含税金额(元)":
-                            sums[index] = this.tableSum.noTaxPriceSum;
-                            break;
-                        //不需要计算合计的列就展示‘--’
-                        default:
-                            sums[index] = "";
-                            break;
-                    }
-                });
-                return sums;
-            },
-            calcuSum() {
-                var itemPriceSum = 0;
-                var taxPriceSum = 0;
-                var noTaxPriceSum = 0;
-                var len = this.dataList.length;
-                for (var i = 0; i < len; i++) {
-                    itemPriceSum = (itemPriceSum * 100 + this.dataList[i].itemPrice * 100) / 100;
-                    taxPriceSum = (taxPriceSum * 100 + this.dataList[i].taxPrice * 100) / 100;
-                    noTaxPriceSum = (noTaxPriceSum * 100 + this.dataList[i].noTaxPrice * 100) / 100;
-                }
-                this.tableSum.itemPriceSum = itemPriceSum;
-                this.tableSum.taxPriceSum = Number(taxPriceSum).toFixed(2);
-                this.tableSum.noTaxPriceSum = Number(noTaxPriceSum).toFixed(2);
+			</el-dialog>
+		</div>
+		<script>
+			var app = new Vue({
+				components: {
+					"sa-item": httpVueLoader('../../sa-frame/com/sa-item.vue'),  
+					"sa-td": httpVueLoader('../../sa-frame/com/sa-td.vue'),		
+				},
+				el: '.vue-box',
+				data: {
+					p: { // 查询参数  
+						id: '',		// 主键 
+						businessNo: '',		// 业务单号 
+						carNo: '',		// 车牌号
+						feeType: '',		//收费类型
+						itemTypeId: '',		// 业务类型id 
+						itemTypeName: '',		// 业务类型 
+						itemId: '',		//  
+						itemName: '',		// 业务项 
+						itemPrice: '',		// 项目金额(元) 
+						payDay: '',		// 支付日期 
+						payType: '',		// 支付方式(3=微信支付) 
+						createTime: '',		// 创建时间 
+						pageNo: 1,		// 当前页 
+						pageSize: 10,	// 页大小
+						sortType: 11,		// 排序方式
+						type: '',
+						isInvoice: '',   //是否开票
+					},
+					dataCount: 0,
+					dataList: [], // 数据集合
+					itemTypeList: [],
+					selectTime:[],
+					selectTimeRange: {
+						beginTime: '', //查询开始时间
+						endTime: '', //查询结束时间
+					},
+					exportTime:[],
+					emodel: {
+						visible: false,
+						form: {
+							// payDay: ''
+							feeType: '',
+							itemTypeName: '',
+							beginTime: '', //查询开始时间
+							endTime: '', //查询结束时间
+						}
+					},
+					totalPrice: 0,
+					tableSum:{
+						itemPriceSum: 0,
+						taxPriceSum: 0,
+						noTaxPriceSum: 0,
+					},
+				},
+				methods: {
+					getSumRol(param){
+
+						const columns = param.columns;
+						const sums = [];
+						columns.forEach((column, index) => {
+							if (index === 0) {
+								sums[index] = "合计";
+								return;
+							}
+							//根据当前列绑定的字段名进行判断,根据字段名决定展示什么内容
+							switch (column.label) {
+									//金额;
+								case "总价(元)":
+									//在这里你就可以根据需要对数据进行一些处理(保留小数位数,加上单位等)
+									sums[index] = this.tableSum.itemPriceSum;
+									break;
+									//人数
+								case "税款(元)":
+									sums[index] = this.tableSum.taxPriceSum;
+									break;
+									//件数;
+								case "不含税金额(元)":
+									sums[index] = this.tableSum.noTaxPriceSum;
+									break;
+									//不需要计算合计的列就展示‘--’
+								default:
+									sums[index] = "";
+									break;
+							}
+						});
+						return sums;
+					},
+					calcuSum(){
+						var itemPriceSum = 0;
+						var taxPriceSum = 0;
+						var noTaxPriceSum = 0;
+						var len = this.dataList.length;
+						for(var i=0; i<len; i++){
+							itemPriceSum = (itemPriceSum*100 + this.dataList[i].itemPrice*100)/100;
+							taxPriceSum = (taxPriceSum*100 + this.dataList[i].taxPrice*100)/100;
+							noTaxPriceSum = (noTaxPriceSum*100 + this.dataList[i].noTaxPrice*100)/100;
+						}
+						this.tableSum.itemPriceSum = itemPriceSum;
+						this.tableSum.taxPriceSum = Number(taxPriceSum).toFixed(2);
+						this.tableSum.noTaxPriceSum = Number(noTaxPriceSum).toFixed(2);
 
             },
             getTotalPrice() {
@@ -382,195 +377,195 @@
                     }.bind(this))
                 }).catch(() => {
 
-                });
-            },
-            jiChaConfirm() {
-                let selection = this.$refs['data-table'].selection;
-                let ids = sa.getArrayField(selection, 'id');
-                if (selection.length == 0) {
-                    return sa.msg('请至少选择一条数据')
-                }
-                this.$confirm('确定进行稽查确认操作?', '提示', {
-                    confirmButtonText: '确定',
-                    cancelButtonText: '取消',
-                }).then(() => {
-                    sa.ajax('/TbFeeDetails/jiChaConfirm', {ids: ids.join(',')}, function (res) {
-                        this.f5();
-                    }.bind(this))
-                }).catch(() => {
+						});
+					},
+					jiChaConfirm(){
+						let selection = this.$refs['data-table'].selection;
+						let ids = sa.getArrayField(selection, 'id');
+						if(selection.length == 0) {
+							return sa.msg('请至少选择一条数据')
+						}
+						this.$confirm('确定进行稽查确认操作?', '提示', {
+							confirmButtonText: '确定',
+							cancelButtonText: '取消',
+						}).then(() => {
+							sa.ajax('/TbFeeDetails/jiChaConfirm', {ids: ids.join(',')}, function(res) {
+								this.f5();
+							}.bind(this))
+						}).catch(() => {
 
-                });
-            },
-            jiChaCancel() {
-                let selection = this.$refs['data-table'].selection;
-                let ids = sa.getArrayField(selection, 'id');
-                if (selection.length == 0) {
-                    return sa.msg('请至少选择一条数据')
-                }
-                this.$confirm('确定进行开单确认操作?', '提示', {
-                    confirmButtonText: '确定',
-                    cancelButtonText: '取消',
-                    type: 'warning'
-                }).then(() => {
-                    sa.ajax('/TbFeeDetails/jiChaCancel', {ids: ids.join(',')}, function (res) {
-                        this.f5();
-                    }.bind(this))
-                }).catch(() => {
+						});
+					},
+					jiChaCancel(){
+						let selection = this.$refs['data-table'].selection;
+						let ids = sa.getArrayField(selection, 'id');
+						if(selection.length == 0) {
+							return sa.msg('请至少选择一条数据')
+						}
+						this.$confirm('确定进行开单确认操作?', '提示', {
+							confirmButtonText: '确定',
+							cancelButtonText: '取消',
+							type: 'warning'
+						}).then(() => {
+							sa.ajax('/TbFeeDetails/jiChaCancel', {ids: ids.join(',')}, function(res) {
+								this.f5();
+							}.bind(this))
+						}).catch(() => {
 
-                });
-            },
-            print: function () {
-                if (this.selectTime != null && this.selectTime.length != 0) {
-                    this.selectTimeRange.beginTime = this.selectTime[0];
-                    this.selectTimeRange.endTime = this.selectTime[1];
-                }
+						});
+					},
+					print: function() {
+						if ( this.selectTime != null && this.selectTime.length != 0) {
+							this.selectTimeRange.beginTime = this.selectTime[0];
+							this.selectTimeRange.endTime = this.selectTime[1];
+						}
 
-                var beginTime = this.selectTimeRange.beginTime;
-                var endTime = this.selectTimeRange.endTime;
-                var feeType = this.p.feeType;
-                var itemTypeName = this.p.itemTypeName;
+						var beginTime = this.selectTimeRange.beginTime;
+						var endTime = this.selectTimeRange.endTime;
+						var feeType = this.p.feeType;
+						var itemTypeName = this.p.itemTypeName;
 
-                var str = '';
-                if (beginTime === '' && endTime === '') {
-                    str += '所有时间';
-                } else {
-                    str += beginTime + "至" + endTime
-                }
-                if (feeType === '') {
-                    str += "、所有收费项目";
-                } else {
-                    var feeTypeName = '';
-                    if (feeType == 1) {
-                        feeTypeName = "核酸检测";
-                    } else if (feeType == 2) {
-                        feeTypeName = "消杀作业";
-                    } else if (feeType == 3) {
-                        feeTypeName = "装卸作业";
-                    } else if (feeType == 4) {
-                        feeTypeName = "停车费";
-                    } else if (feeType == 5) {
-                        feeTypeName = "过磅费";
-                    } else if (feeType == 6) {
-                        feeTypeName = "入场管理费";
-                    } else if (feeType == 7) {
-                        feeTypeName = "充电打冷作业";
-                    }
-                    str += "、收费项目为" + feeTypeName;
-                }
-                if (itemTypeName === '') {
-                    str += "、所有业务类型";
-                } else {
-                    str += "、业务类型为" + itemTypeName;
-                }
+						var str = '';
+						if(beginTime === '' && endTime === ''){
+							str += '所有时间';
+						}else {
+							str += beginTime + "至" + endTime
+						}
+						if(feeType === ''){
+							str += "、所有收费项目";
+						}else{
+							var feeTypeName = '';
+							if(feeType == 1){
+								feeTypeName = "核酸检测";
+							}else if(feeType == 2){
+								feeTypeName = "消杀作业";
+							}else if(feeType == 3){
+								feeTypeName = "装卸作业";
+							}else if(feeType == 4){
+								feeTypeName = "停车费";
+							}else if(feeType == 5){
+								feeTypeName = "过磅费";
+							}else if(feeType == 6){
+								feeTypeName = "入场管理费";
+							}else if(feeType == 7){
+								feeTypeName = "充电打冷作业";
+							}
+							str += "、收费项目为" + feeTypeName;
+						}
+						if(itemTypeName === ''){
+							str += "、所有业务类型";
+						}else{
+							str += "、业务类型为" + itemTypeName;
+						}
 
-                this.$confirm('确定打印' + str + '的数据?', '提示', {
-                    confirmButtonText: '确定',
-                    cancelButtonText: '取消',
-                    type: 'warning'
-                }).then(() => {
-                    sa.showIframe('打印申报信息表', 'detailPrint.html?beginTime=' + beginTime + "&endTime=" + endTime + "&feeType=" + feeType + "&itemTypeName=" + itemTypeName, '1000px', '100%');
-                }).catch(() => {
+						this.$confirm('确定打印'+str+'的数据?', '提示', {
+							confirmButtonText: '确定',
+							cancelButtonText: '取消',
+							type: 'warning'
+						}).then(() => {
+							sa.showIframe('打印申报信息表', 'detailPrint.html?beginTime='+beginTime+"&endTime="+endTime+"&feeType="+feeType+"&itemTypeName="+itemTypeName , '1000px', '100%');
+						}).catch(() => {
 
-                });
-            },
-            exportFn() {
-                if (this.selectTime != null && this.selectTime.length != 0) {
-                    this.selectTimeRange.beginTime = this.selectTime[0];
-                    this.selectTimeRange.endTime = this.selectTime[1];
-                }
+						});
+					},
+					exportFn() {
+						if ( this.selectTime != null && this.selectTime.length != 0) {
+							this.selectTimeRange.beginTime = this.selectTime[0];
+							this.selectTimeRange.endTime = this.selectTime[1];
+						}
 
-                var beginTime = this.selectTimeRange.beginTime;
-                var endTime = this.selectTimeRange.endTime;
-                var feeType = this.p.feeType;
-                var itemTypeName = this.p.itemTypeName;
-                var str = '';
-                if (beginTime === '' && endTime === '') {
-                    str += '所有时间';
-                } else {
-                    str += beginTime + "至" + endTime
-                }
-                if (feeType === '') {
-                    str += "、所有收费项目";
-                } else {
-                    var feeTypeName = '';
-                    if (feeType == 1) {
-                        feeTypeName = "核酸检测";
-                    } else if (feeType == 2) {
-                        feeTypeName = "消杀作业";
-                    } else if (feeType == 3) {
-                        feeTypeName = "装卸作业";
-                    } else if (feeType == 4) {
-                        feeTypeName = "停车费";
-                    } else if (feeType == 5) {
-                        feeTypeName = "过磅费";
-                    } else if (feeType == 6) {
-                        feeTypeName = "入场管理费";
-                    } else if (feeType == 7) {
-                        feeTypeName = "充电打冷作业";
-                    }
-                    str += "、收费项目为" + feeTypeName;
-                }
-                if (itemTypeName === '') {
-                    str += "、所有业务类型";
-                } else {
-                    str += "、业务类型为" + itemTypeName;
-                }
+						var beginTime = this.selectTimeRange.beginTime;
+						var endTime = this.selectTimeRange.endTime;
+						var feeType = this.p.feeType;
+						var itemTypeName = this.p.itemTypeName;
+						var str = '';
+						if(beginTime === '' && endTime === ''){
+							str += '所有时间';
+						}else {
+							str += beginTime + "至" + endTime
+						}
+						if(feeType === ''){
+							str += "、所有收费项目";
+						}else{
+							var feeTypeName = '';
+							if(feeType == 1){
+								feeTypeName = "核酸检测";
+							}else if(feeType == 2){
+								feeTypeName = "消杀作业";
+							}else if(feeType == 3){
+								feeTypeName = "装卸作业";
+							}else if(feeType == 4){
+								feeTypeName = "停车费";
+							}else if(feeType == 5){
+								feeTypeName = "过磅费";
+							}else if(feeType == 6){
+								feeTypeName = "入场管理费";
+							}else if(feeType == 7){
+								feeTypeName = "充电打冷作业";
+							}
+							str += "、收费项目为" + feeTypeName;
+						}
+						if(itemTypeName === ''){
+							str += "、所有业务类型";
+						}else{
+							str += "、业务类型为" + itemTypeName;
+						}
 
-                this.$confirm('确定导出' + str + '的数据?', '提示', {
-                    confirmButtonText: '确定',
-                    cancelButtonText: '取消',
-                    type: 'warning'
-                }).then(() => {
-                    sa.ajax('/TbFeeDetails/export/details?beginTime=' + this.selectTimeRange.beginTime + '&endTime=' + this.selectTimeRange.endTime
-                        , sa.removeNull(this.p), function (resp) {
-                            window.open(resp.data);
-                        }.bind(this));
-                }).catch(() => {
+						this.$confirm('确定导出'+str+'的数据?', '提示', {
+							confirmButtonText: '确定',
+							cancelButtonText: '取消',
+							type: 'warning'
+						}).then(() => {
+							sa.ajax('/TbFeeDetails/export/details?beginTime='+this.selectTimeRange.beginTime+'&endTime='+this.selectTimeRange.endTime
+									, sa.removeNull(this.p),  function(resp) {
+								window.open(resp.data);
+							}.bind(this));
+						}).catch(() => {
 
-                });
-            },
-            // 刷新
-            f5: function () {
-                if (this.selectTime != null && this.selectTime.length != 0) {
-                    this.selectTimeRange.beginTime = this.selectTime[0];
-                    this.selectTimeRange.endTime = this.selectTime[1];
-                }
-                sa.ajax('/TbFeeDetails/getList?beginTime=' + this.selectTimeRange.beginTime + '&endTime=' + this.selectTimeRange.endTime,
-                    sa.removeNull(this.p), function (res) {
-                        this.dataList = res.data; // 数据
-                        this.dataCount = res.dataCount; // 数据总数
-                        sa.f5TableHeight();		// 刷新表格高度
-                    }.bind(this));
-                this.getTotalPrice();
-            },
-            // 查看
-            get: function (data) {
-                sa.showIframe('数据详情', 'tb-fee-details-info.html?id=' + data.id, '1050px', '90%');
-            },
-            // 查看 - 根据选中的
-            getBySelect: function (data) {
-                var selection = this.$refs['data-table'].selection;
-                if (selection.length == 0) {
-                    return sa.msg('请选择一条数据')
-                }
-                this.get(selection[0]);
-            },
-            getItemTypeList() {
-                sa.ajax('/TbItemType/getList', {
-                    pageNo: 1,
-                    pageSize: 100
-                }, function (resp) {
-                    this.itemTypeList = resp.data;
-                }.bind(this));
-            },
+						});
+					},
+					// 刷新
+					f5: function() {
+						if ( this.selectTime != null && this.selectTime.length != 0) {
+							this.selectTimeRange.beginTime = this.selectTime[0];
+							this.selectTimeRange.endTime = this.selectTime[1];
+						}
+						sa.ajax('/TbFeeDetails/getList?beginTime='+this.selectTimeRange.beginTime+'&endTime='+this.selectTimeRange.endTime,
+								sa.removeNull(this.p), function(res) {
+							this.dataList = res.data; // 数据
+							this.dataCount = res.dataCount; // 数据总数 
+							sa.f5TableHeight();		// 刷新表格高度
+						}.bind(this));
+						this.getTotalPrice();
+					},
+					// 查看
+					get: function(data) {
+						sa.showIframe('数据详情', 'tb-fee-details-info.html?id=' + data.id, '1050px', '90%');
+					},
+					// 查看 - 根据选中的
+					getBySelect: function(data) {
+						var selection = this.$refs['data-table'].selection;
+						if(selection.length == 0) {
+							return sa.msg('请选择一条数据')
+						}
+						this.get(selection[0]);
+					},
+					getItemTypeList() {
+						sa.ajax('/TbItemType/getList', {
+							pageNo: 1,
+							pageSize: 100
+						}, function(resp) {
+							this.itemTypeList = resp.data;
+						}.bind(this));
+					},
 
-        },
-        created: function () {
-            this.f5();
-            this.getItemTypeList();
-            sa.onInputEnter();
-        }
-    })
-</script>
-</body>
+				},
+				created: function() {
+					this.f5();
+					this.getItemTypeList();
+					sa.onInputEnter();
+				}
+			})
+		</script>
+	</body>
 </html>

+ 219 - 0
sp-admin/sa-view/tb-invoice-info/online-invioce.html

@@ -0,0 +1,219 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>线上开票确认</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <meta name="viewport"
+          content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
+    <!-- 所有的 css js 资源 -->
+    <link rel="stylesheet" href="../../static/kj/element-ui/theme-chalk/index.css">
+    <link rel="stylesheet" href="../../static/sa.css">
+    <script src="../../static/kj/vue.min.js"></script>
+    <script src="../../static/kj/element-ui/index.js"></script>
+    <script src="../../static/kj/httpVueLoader.js"></script>
+    <script src="../../static/kj/jquery.min.js"></script>
+    <script src="../../static/kj/layer/layer.js"></script>
+    <script src="../../static/sa.js"></script>
+    <style type="text/css">
+        .c-panel .c-label {
+            width: 8em;
+        }
+    </style>
+</head>
+<body>
+<div class="vue-box sbot" style="display: none;" :style="'display: block;'">
+    <!-- ------- 内容部分 ------- -->
+    <div class="s-body">
+        <div class="c-panel">
+            <el-form>
+                <el-row>
+                    <el-collapse value='1'>
+                        <el-collapse-item name="1">
+                            <div slot="title">
+                                基础信息
+                            </div>
+                            <div>
+                                <el-row>
+                                    <el-col span="12">
+                                        <sa-info name="开票总额" br>{{m.totalMoney}}元</sa-info>
+                                        <sa-info name="主体名称" br>{{m.entityName}}</sa-info>
+                                        <sa-info name="税号" br>{{m.taxIdNo}}</sa-info>
+
+                                    </el-col>
+                                    <el-col span="12">
+                                        <sa-info name="开户银行" br>{{m.bank}}</sa-info>
+                                        <sa-info name="银行账号" br>{{m.bankNo}}</sa-info>
+                                        <sa-info name="地址" br>{{m.address}}</sa-info>
+                                        <sa-info name="电话" br>{{m.phone}}</sa-info>
+                                        <sa-info name="邮箱" br>{{m.email}}</sa-info>
+                                    </el-col>
+                                </el-row>
+                            </div>
+                        </el-collapse-item>
+                    </el-collapse>
+                </el-row>
+                <el-row>
+                    <el-collapse value='1'>
+                        <el-collapse-item name="1">
+                            <div slot="title">
+                                实际开票
+                            </div>
+                            <el-table :data="invioceDetails" style="width: 100%">
+                                <el-table-column type="index" width="50" label="序号"></el-table-column>
+                                <el-table-column label="单据编号" prop="id"></el-table-column>
+                                <el-table-column label="金额(元)" prop="money"></el-table-column>
+                                <el-table-column label="发票号" prop="invoiceNo"></el-table-column>
+                                <el-table-column label="发票代码" prop="invoiceCode"></el-table-column>
+                                <el-table-column label="发票预览">
+                                    <template slot-scope="s" >
+                                        <img v-if="s.row.imageUrl" :src="s.row.imageUrl" class="td-img" @click="sa.showImage(s.row.imageUrl, '400px', '400px')" />
+                                        <span v-else></span>
+                                    </template>
+                                </el-table-column>
+                                <sa-td name="发票预览" prop="imageUrl" type="img"></sa-td>
+                                <el-table-column label="操作"  width="140px">
+                                    <template slot-scope="s">
+                                        <el-button class="c-btn" type="success"  @click="showFee(s.row.id)">费用详情</el-button>
+                                    </template>
+                                </el-table-column>
+                            </el-table>
+
+                        </el-collapse-item>
+                    </el-collapse>
+                </el-row>
+
+            </el-form>
+        </div>
+    </div>
+    <!-- ------- 底部按钮 ------- -->
+    <div class="s-foot">
+        <el-button v-if="m.applyAble!=1&&m.isApply!=1&&m.isApply!=2&&comfirmButton==0&&m.status==0&&currentCustomerId==1" type="success" @click="comfirmFn">确定开票</el-button>
+        <el-button @click="sa.closeCurrIframe()">取消</el-button>
+    </div>
+    <el-dialog title="费用明细" :visible.sync="showFeeDate.visible" width="90%">
+        <el-table :data="feeDetails" style="width: 100%">
+            <el-table-column label="业务类型" prop="itemTypeName" ></el-table-column>
+            <el-table-column label="数量" prop="num" ></el-table-column>
+            <el-table-column label="单价(元)" prop="unitPrice" ></el-table-column>
+            <el-table-column label="总价(元)" prop="itemPrice" ></el-table-column>
+            <el-table-column label="税率(%)" >
+                <template slot-scope="s">
+                    <span>{{s.row.taxRate * 100}}</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="税款(元)" >
+                <template slot-scope="s">
+                    <span>{{Number(s.row.taxPrice).toFixed(2)}}</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="不含税金额(元)" >
+                <template slot-scope="s">
+                    <span>{{Number(s.row.noTaxPrice).toFixed(2)}}</span>
+                </template>
+            </el-table-column>
+
+        </el-table>
+        <span slot="footer" class="dialog-footer">
+					<el-button @click="showFeeDate.visible = false">关闭</el-button>
+				</span>
+    </el-dialog>
+    <el-dialog title="请填写开票人" :visible.sync="drawerDate.visible" width="38%">
+        <div class="c-item">
+            <label class="c-label">开票人:</label>
+            <el-input type="text" v-model="drawerDate.form.drawer"></el-input>
+        </div>
+        <span slot="footer" class="dialog-footer">
+            <el-button @click="drawerDate.visible = false">取 消</el-button>
+            <el-button type="primary" @click="comfirm">确 定</el-button>
+        </span>
+    </el-dialog>
+</div>
+<script>
+    var app = new Vue({
+        components: {
+            "sa-info": httpVueLoader('../../sa-frame/com/sa-info.vue')
+        },
+        el: '.vue-box',
+        data: {
+            infoId: sa.p('id', 0),	// 获取数据ID
+            m: null,
+            invioceDetails: [],
+            feeDetails:[],
+            showFeeDate: {
+                visible: false,
+            },
+            comfirmButton: 0,
+            drawerDate: {
+                visible: false,
+                form: {
+                    infoId: sa.p('id', 0),
+                    drawer:"",
+                }
+            },
+            currentCustomerId: '1',
+        },
+        methods: {
+            getCustomer() {
+                sa.ajax('/TbCostomer/getCurrentCustomerId', function(resp) {
+                    this.currentCustomerId = resp.data;
+                }.bind(this));
+            },
+            showFee(id){
+                sa.ajax('/TbInvoiceDetails/groupFeeDetails?id=' + id, function (res) {
+                    this.feeDetails = res.data;
+                    this.showFeeDate.visible = true;
+                }.bind(this))
+            },
+            comfirmFn() {
+                // this.drawerDate.visible = true;
+                this.$confirm('    点击确定开始开票', '提示', {
+                    confirmButtonText: '确定',
+                    cancelButtonText: '取消',
+                    type: ''
+                }).then(() => {
+                    sa.ajax('/InvoiceApply/applyInvoice?infoId='+this.infoId, function(resp) {
+                        if(resp.code == 200){
+                            this.comfirmButton = 1;
+                            sa.alert('开票成功', this.close);
+                        }else{
+                            sa.alert('开票失败', this.close);
+                        }
+                    }.bind(this));
+                });
+            },
+            comfirm() {
+                sa.checkNull(this.drawerDate.form.drawer, '输入 [开票人]');
+                sa.ajax('/InvoiceApply/applyInvoice', this.drawerDate.form, function () {
+                    this.drawerDate.visible = false;
+                    this.comfirmButton = 1;
+                    sa.alert('开票成功', this.close);
+                }.bind(this))
+            },
+            close(){
+                parent.app.f5();
+                sa.closeCurrIframe();
+            },
+            getInfo() {
+                sa.ajax('/TbInvoiceInfo/getById?id=' + this.infoId, function(res) {
+                    this.m = res.data;
+                    if(res.data == null) {
+                        sa.alert('未能查找到 id=' + this.infoId + " 开票信息数据");
+                    }
+                }.bind(this))
+            },
+            getDetails() {
+                sa.ajax('/TbInvoiceDetails/onlineInvoice?infoId=' + this.infoId, function (res) {
+                    this.invioceDetails = res.data;
+                }.bind(this))
+            }
+        },
+        mounted: function () {
+            this.getCustomer();
+            this.getInfo();
+            this.getDetails();
+        }
+    })
+
+</script>
+</body>
+</html>

+ 14 - 10
sp-admin/sa-view/tb-invoice-info/tb-invoice-info-list.html

@@ -52,14 +52,8 @@
 					<sa-td name="开票状态" prop="status" type="enum" :jv="{0: '未开票', 1: '已开票'}"></sa-td>
 					<sa-td name="开票种类" prop="isElec" type="enum" :jv="{0: '纸质普票', 1: '电子普票', 2:'纸质专票'}"></sa-td>
 					<sa-td name="开票时间" prop="invoiceTime" ></sa-td>
-					<sa-td name="发票号" prop="invoiceNo" width="150">
-						<template slot-scope="s">
-							<div>{{s.row.invoiceNo}}
-							<i @click="updateInvoiceNo(s.row)" class="el-icon-edit" v-if="s.row.status===1&& currentCustomerId==1" style="cursor: pointer;padding-left: 10px;color: blue;"></i>
-							</div>
-						</template>
-					</sa-td>
-					<el-table-column label="主体名称" width="180">
+					<sa-td name="发票号" prop="invoiceNo" width="150"></sa-td>
+					<el-table-column label="主体名称">
 						<template slot-scope="s">
 							<span>{{s.row.entityName}}</span>
 						</template>
@@ -69,9 +63,16 @@
 							<span>{{s.row.taxIdNo}}</span>
 						</template>
 					</el-table-column>
-					<el-table-column label="操作"  width="280px">
+<!--					<sa-td name="地址" prop="address" ></sa-td>-->
+<!--					<sa-td name="电话" prop="phone" ></sa-td>-->
+<!--					<sa-td name="开户银行" prop="bank" ></sa-td>-->
+<!--					<sa-td name="银行账号" prop="bankNo" ></sa-td>-->
+<!--					<sa-td name="邮箱" prop="email" ></sa-td>-->
+					<el-table-column label="操作"  width="240px">
 						<template slot-scope="s">
+<!--							<el-button v-if="s.row.isElec==1&&currentCustomerId==1&&s.row.status==0" class="c-btn" type="primary"  @click="onlineFn(s.row)">线上开票</el-button>-->
 							<el-button v-if="s.row.status==0 && currentCustomerId==1" class="c-btn" type="primary"  @click="completeFn(s.row.id)">线下开票</el-button>
+<!--							<el-button v-if="s.row.isElec==1&&s.row.status==1" class="c-btn" type="primary"  @click="onlineFn(s.row)">发票详情</el-button>-->
 							<el-button class="c-btn" type="success" icon="el-icon-view" @click="get(s.row)">查看</el-button>
 							<el-button v-if="s.row.status==0" class="c-btn" type="primary" icon="el-icon-edit" @click="update(s.row)">修改</el-button>
 							<el-button v-if="s.row.status==0 && currentCustomerId==1" class="c-btn" type="danger" icon="el-icon-delete" @click="del(s.row)">删除</el-button>
@@ -81,7 +82,7 @@
 				<!-- ------------- 分页 ------------- -->
 				<sa-item type="page" :curr.sync="p.pageNo" :size.sync="p.pageSize" :total="dataCount" @change="f5()"></sa-item>
 			</div>
-			<el-dialog title="线下开票" :visible.sync="completeDate.visible" width="400px">
+			<el-dialog title="完成开票" :visible.sync="completeDate.visible" width="38%">
 				<div class="c-item">
 					<label class="c-label">开票时间:</label>
 					<el-date-picker type="datetime" value-format="yyyy-MM-dd HH:mm:ss" v-model="completeDate.form.invoiceTime"></el-date-picker>
@@ -143,6 +144,9 @@
 					},
 				},
 				methods: {
+					// onlineFn(data){
+					// 	sa.showIframe('线上开票', 'online-invioce.html?id=' + data.id, '1000px', '90%');
+					// },
 					updateInvoiceNo(data){
 						layer.prompt({title: '修改发票号'}, function(pass, index){
 							layer.close(index);

+ 123 - 127
sp-admin/sa-view/tb-invoice-order/tb-invoice-order-add.html

@@ -1,131 +1,127 @@
 <!DOCTYPE html>
 <html>
-<head>
-    <title>开票订单表-添加/修改</title>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-    <meta name="viewport"
-          content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
-    <!-- 所有的 css js 资源 -->
-    <link rel="stylesheet" href="../../static/kj/element-ui/theme-chalk/index.css">
-    <link rel="stylesheet" href="../../static/sa.css">
-    <script src="../../static/kj/vue.min.js"></script>
-    <script src="../../static/kj/element-ui/index.js"></script>
-    <script src="../../static/kj/httpVueLoader.js"></script>
-    <script src="../../static/kj/jquery.min.js"></script>
-    <script src="../../static/kj/layer/layer.js"></script>
-    <script src="../../static/sa.js"></script>
-    <script src="../../static/kj/upload-util.js"></script>
-    <style type="text/css">
-        .c-panel .el-form .c-label {
-            width: 7em !important;
-        }
+	<head>
+		<title>开票订单表-添加/修改</title>
+		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
+		<!-- 所有的 css js 资源 -->
+		<link rel="stylesheet" href="../../static/kj/element-ui/theme-chalk/index.css">
+		<link rel="stylesheet" href="../../static/sa.css">
+		<script src="../../static/kj/vue.min.js"></script>
+		<script src="../../static/kj/element-ui/index.js"></script>
+		<script src="../../static/kj/httpVueLoader.js"></script>
+		<script src="../../static/kj/jquery.min.js"></script>
+		<script src="../../static/kj/layer/layer.js"></script>
+		<script src="../../static/sa.js"></script>
+		<script src="../../static/kj/upload-util.js"></script>
+		<style type="text/css">
+			.c-panel .el-form .c-label{width: 7em !important;}
+			.c-panel .el-form .el-input, .c-panel .el-form .el-textarea__inner{width: 250px;}
+		</style>
+	</head>
+	<body>
+		<div class="vue-box" :class="{sbot: id}" style="display: none;" :style="'display: block;'">
+			<!-- ------- 内容部分 ------- -->
+			<div class="s-body">
+				<div class="c-panel">
+                    <div class="c-title" v-if="id == 0">上传账单</div>
+					<div class="c-title" v-else>数据修改</div>
+					<el-form v-if="m">
+						<sa-item v-if="idShow === 1" type="text" name="交易单号" v-model="m.transactionId" placeholder="请填写账单中的交易单号" br></sa-item>
+<!--						<sa-item type="text" name="账单金额" v-model="m.billMoney" br></sa-item>-->
+						<sa-item type="img" name="账单截图" v-model="m.billImage" br></sa-item>
+						<sa-item name="" class="s-ok" br>
+							<el-button type="primary" icon="el-icon-plus" @click="ok()">保存</el-button>
+						</sa-item>
+					</el-form>
+				</div>
+			</div>
+			<!-- ------- 底部按钮 ------- -->
+			<div class="s-foot">
+				<el-button type="primary" @click="ok()">确定</el-button>
+				<el-button @click="sa.closeCurrIframe()">取消</el-button>
+			</div>
+		</div>
+        <script>
+			
+			var app = new Vue({
+				components: {
+					"sa-item": httpVueLoader('../../sa-frame/com/sa-item.vue')
+				},
+				el: '.vue-box',
+				data: {
+					id: sa.p('id', 0),		// 获取超链接中的id参数(0=添加,非0=修改) 
+					m: null,		// 实体对象
+					idShow: 0,
+				},
+				methods: {
+					// 创建一个 默认Model 
+					createModel: function() {
+						return {
+							id: '',		// 主键
+							customerId: sa.p('customerId', ''),
+							businessId: '',		// 业务订单id 
+							businessName: '',		// 业务名称 
+							businessNo: '',		// 业务订单号 
+							transactionId: '',		// 微信支付订单号 
+							billMoney: '',		// 账单金额 
+							billImage: '',		// 账单截图 
+							status: '',		// 支付状态(0=未开票,1=已开票) 
+							invoiceTime: '',		// 开票时间 
+							createTime: '',		// 创建时间 
+							infoId: '',		// 开票信息id 
+						}
+					},
+					// 提交数据 
+					ok: function(){
+						// 表单校验 
+						let m = this.m;
+						// sa.checkNull(m.transactionId, '请输入 [微信支付订单号]');
+						// sa.checkNull(m.billMoney, '请输入 [账单金额]');
+						sa.checkNull(m.billImage, '请输入 [账单截图]');
+				
+						// 开始增加或修改
+						if(this.id <= 0) {	// 添加
+							sa.ajax('/TbInvoiceOrder/add', m, function(res){
+								if(res.msg === 'ok'){
+									sa.alert('增加成功', this.clean);
+								}else if(res.msg === 'fail'){
+									this.idShow = 1;
+									if(this.m.transactionId === ''){
+										sa.alert('失败:截图无法识别,或不存在与该账单关联的业务订,请填写截图中的交易单号。');
+									}else {
+										sa.alert('失败:不存在与该交易单号关联的业务订单');
+									}
 
-        .c-panel .el-form .el-input, .c-panel .el-form .el-textarea__inner {
-            width: 250px;
-        }
-    </style>
-</head>
-<body>
-<div class="vue-box" :class="{sbot: id}" style="display: none;" :style="'display: block;'">
-    <!-- ------- 内容部分 ------- -->
-    <div class="s-body">
-        <div class="c-panel">
-            <div class="c-title" v-if="id == 0">上传账单</div>
-            <div class="c-title" v-else>数据修改</div>
-            <el-form v-if="m">
-                <sa-item v-if="idShow === 1" type="text" name="交易单号" v-model="m.transactionId" placeholder="请填写账单中的交易单号"
-                         br></sa-item>
-                <!--						<sa-item type="text" name="账单金额" v-model="m.billMoney" br></sa-item>-->
-                <sa-item type="img" name="账单截图" v-model="m.billImage" br></sa-item>
-                <sa-item name="" class="s-ok" br>
-                    <el-button type="primary" icon="el-icon-plus" @click="ok()">保存</el-button>
-                </sa-item>
-            </el-form>
-        </div>
-    </div>
-    <!-- ------- 底部按钮 ------- -->
-    <div class="s-foot">
-        <el-button type="primary" @click="ok()">确定</el-button>
-        <el-button @click="sa.closeCurrIframe()">取消</el-button>
-    </div>
-</div>
-<script>
-
-    var app = new Vue({
-        components: {
-            "sa-item": httpVueLoader('../../sa-frame/com/sa-item.vue')
-        },
-        el: '.vue-box',
-        data: {
-            id: sa.p('id', 0),		// 获取超链接中的id参数(0=添加,非0=修改)
-            m: null,		// 实体对象
-            idShow: 0,
-        },
-        methods: {
-            // 创建一个 默认Model
-            createModel: function () {
-                return {
-                    id: '',		// 主键
-                    customerId: sa.p('customerId', ''),
-                    businessId: '',		// 业务订单id
-                    businessName: '',		// 业务名称
-                    businessNo: '',		// 业务订单号
-                    transactionId: '',		// 微信支付订单号
-                    billMoney: '',		// 账单金额
-                    billImage: '',		// 账单截图
-                    status: '',		// 支付状态(0=未开票,1=已开票)
-                    invoiceTime: '',		// 开票时间
-                    createTime: '',		// 创建时间
-                    infoId: '',		// 开票信息id
-                }
-            },
-            // 提交数据
-            ok: function () {
-                // 表单校验
-                let m = this.m;
-                // sa.checkNull(m.transactionId, '请输入 [微信支付订单号]');
-                // sa.checkNull(m.billMoney, '请输入 [账单金额]');
-                sa.checkNull(m.billImage, '请输入 [账单截图]');
-
-                // 开始增加或修改
-                if (this.id <= 0) {	// 添加
-                    sa.ajax('/TbInvoiceOrder/add', m, function (res) {
-                        console.log("执行了");
-                        if (res.msg === 'ok') {
-                            sa.alert('增加成功', this.clean);
-                        } else if (res.msg === 'fail') {
-                            console.log("执行了");
-                            this.idShow = 1;
-                            sa.alert('失败:截图无法识别,或不存在与该账单关联的业务订单,请填写截图中的交易单号。');
-                        }
-                    }.bind(this));
-                }
-            },
-            // 添加/修改 完成后的动作
-            clean: function () {
-                if (this.id == 0) {
-                    this.m = this.createModel();
-                } else {
-                    parent.app.f5();		// 刷新父页面列表
-                    sa.closeCurrIframe();	// 关闭本页
-                }
-            }
-        },
-        mounted: function () {
-            // 初始化数据
-            if (this.id <= 0) {
-                this.m = this.createModel();
-            } else {
-                sa.ajax('/TbInvoiceOrder/getById?id=' + this.id, function (res) {
-                    this.m = res.data;
-                    if (res.data == null) {
-                        sa.alert('未能查找到 id=' + this.id + " 详细数据");
-                    }
-                }.bind(this))
-            }
-        }
-    })
-
-</script>
-</body>
+								}
+							}.bind(this));
+						}
+					},
+					// 添加/修改 完成后的动作
+					clean: function() {
+						if(this.id == 0) {
+							this.m = this.createModel();
+						} else {
+							parent.app.f5();		// 刷新父页面列表
+							sa.closeCurrIframe();	// 关闭本页 
+						}
+					}
+				},
+				mounted: function(){
+					// 初始化数据 
+					if(this.id <= 0) {	
+						this.m = this.createModel();
+					} else {	
+						sa.ajax('/TbInvoiceOrder/getById?id=' + this.id, function(res) {
+							this.m = res.data;
+							if(res.data == null) {
+								sa.alert('未能查找到 id=' + this.id + " 详细数据");
+							}
+						}.bind(this))
+					}
+				}
+			})
+			
+		</script>
+	</body>
 </html>

+ 258 - 268
sp-admin/sa-view/tb-invoice-order/tb-invoice-order-list.html

@@ -1,279 +1,269 @@
 <!DOCTYPE html>
 <html>
-<head>
-    <title>开票订单表-列表</title>
-    <meta charset="utf-8">
-    <meta name="viewport"
-          content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
-    <!-- 所有的 css & js 资源 -->
-    <link rel="stylesheet" href="../../static/kj/element-ui/theme-chalk/index.css">
-    <link rel="stylesheet" href="../../static/sa.css">
-    <script src="../../static/kj/vue.min.js"></script>
-    <script src="../../static/kj/element-ui/index.js"></script>
-    <script src="../../static/kj/httpVueLoader.js"></script>
-    <script src="../../static/kj/jquery.min.js"></script>
-    <script src="../../static/kj/layer/layer.js"></script>
-    <script src="../../static/sa.js"></script>
-</head>
-<style>
-    .c1-label {
-        width: 7em;
-        color: #333;
-        padding-right: 4px;
-        display: inline-block;
-        text-align: right;
-        vertical-align: top;
-    }
-</style>
-<body>
-<div class="vue-box" style="display: none;" :style="'display: block;'">
-    <div class="c-panel">
-        <!-- ------------- 检索参数 ------------- -->
-        <div class="c-title">检索参数</div>
-        <el-form ref="form" :model='p' @submit.native.prevent>
-            <div class="c-item">
-                <label class="c1-label">开票信息编号:</label>
-                <el-input type="text" v-model="p.infoNo"></el-input>
-            </div>
-            <div class="c-item">
-                <label class="c1-label">车牌号:</label>
-                <el-input type="text" v-model="p.carNo"></el-input>
-            </div>
-            <div class="c-item">
-                <label class="c1-label">微信支付订单:</label>
-                <el-input type="text" v-model="p.transactionId"></el-input>
-            </div>
-            <div class="c-item">
-                <label class="c-label">开票状态:</label>
-                <el-select v-model="p.status" placeholder="请选择">
-                    <el-option label="不限" value=""></el-option>
-                    <el-option label="待申请" :value="0"></el-option>
-                    <el-option label="已申请" :value="1"></el-option>
-                    <el-option label="已开票" :value="2"></el-option>
-                </el-select>
-            </div>
-            <el-button type="primary" icon="el-icon-search" @click="p.pageNo = 1; f5()">查询</el-button>
-            <el-button size="mini" type="info" @click="sa.f5()">刷新</el-button>
-            <br/>
-        </el-form>
-        <!-- ------------- 快捷按钮 ------------- -->
-        <el-form ref="form" :model='p' @submit.native.prevent>
-            <el-button style="display: inline;" type="primary" @click="add()">上传账单截图</el-button>
-            <el-button style="display: inline;" type="primary" @click="applyFn()">申请开票</el-button>
-        </el-form>
-        <!-- ------------- 数据列表 ------------- -->
-        <el-table class="data-table" ref="data-table" :data="dataList">
-            <sa-td type="selection"></sa-td>
+	<head>
+		<title>开票订单表-列表</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
+		<!-- 所有的 css & js 资源 -->
+		<link rel="stylesheet" href="../../static/kj/element-ui/theme-chalk/index.css">
+		<link rel="stylesheet" href="../../static/sa.css">
+		<script src="../../static/kj/vue.min.js"></script>
+		<script src="../../static/kj/element-ui/index.js"></script>
+		<script src="../../static/kj/httpVueLoader.js"></script>
+		<script src="../../static/kj/jquery.min.js"></script>
+		<script src="../../static/kj/layer/layer.js"></script>
+		<script src="../../static/sa.js"></script>
+	</head>
+	<style>
+		.c1-label{width: 7em; color: #333; padding-right: 4px; display: inline-block; text-align: right; vertical-align: top;}
+	</style>
+	<body>
+		<div class="vue-box" style="display: none;" :style="'display: block;'">
+			<div class="c-panel">
+				<!-- ------------- 检索参数 ------------- -->
+				<div class="c-title">检索参数</div>
+				<el-form ref="form" :model='p' @submit.native.prevent>
+					<div class="c-item">
+						<label class="c1-label">开票信息编号:</label>
+						<el-input type="text" v-model="p.infoNo"></el-input>
+					</div>
+					<div class="c-item">
+						<label class="c1-label">车牌号:</label>
+						<el-input type="text" v-model="p.carNo"></el-input>
+					</div>
+					<div class="c-item">
+						<label class="c1-label">微信支付订单:</label>
+						<el-input type="text" v-model="p.transactionId"></el-input>
+					</div>
+					<div class="c-item">
+						<label class="c-label">开票状态:</label>
+						<el-select v-model="p.status" placeholder="请选择">
+							<el-option label="不限" value=""></el-option>
+							<el-option label="待申请" :value="0"></el-option>
+							<el-option label="已申请" :value="1"></el-option>
+							<el-option label="已开票" :value="2"></el-option>
+						</el-select>
+					</div>
+					<el-button type="primary" icon="el-icon-search" @click="p.pageNo = 1; f5()">查询</el-button>
+					<el-button size="mini" type="info" @click="sa.f5()">刷新</el-button>
+					<br /><br />
+				</el-form>
+				<!-- ------------- 快捷按钮 ------------- -->
+				<el-form ref="form" :model='p' @submit.native.prevent>
+					<el-button style="display: inline;" type="primary"  @click="add()">上传账单截图</el-button>
+					<el-button style="display: inline;" type="primary"  @click="applyFn()">申请开票</el-button>
+				</el-form>
+				<!-- ------------- 数据列表 ------------- -->
+				<el-table class="data-table" ref="data-table" :data="dataList" >
+					<sa-td type="selection"></sa-td>
 
-            <sa-td name="业务名称" prop="businessName" width="150px"></sa-td>
-            <sa-td name="车牌号" prop="carNo" width="150px"></sa-td>
-            <el-table-column label="业务订单号" width="150px">
-                <template slot-scope="s">
-                    <el-tooltip :content="s.row.businessNo" placement="bottom" effect="light">
-                        <el-button class="keyButton">{{ s.row.businessNo }}</el-button>
-                    </el-tooltip>
-                </template>
-            </el-table-column>
-            <!--					<sa-td name="业务订单号" prop="businessNo" width="150" ></sa-td>-->
-            <sa-td name="微信支付订单号" prop="transactionId" width="210px"></sa-td>
-            <sa-td name="账单金额" prop="billMoney"></sa-td>
-            <sa-td name="账单截图" prop="billImage" type="img"></sa-td>
-            <sa-td name="开票状态" prop="status" type="enum" :jv="{0: '待申请', 1: '已申请', 2: '已开票'}"></sa-td>
-            <sa-td name="开票时间" prop="invoiceTime" width="140px"></sa-td>
-            <sa-td name="开票信息" prop="infoNo" width="130"></sa-td>
-            <el-table-column label="操作" fixed="right" width="240px">
-                <template slot-scope="s">
-                    <el-button class="c-btn" type="success" icon="el-icon-view" @click="get(s.row)">查看</el-button>
-                    <el-button v-if="s.row.status==0" class="c-btn" type="danger" icon="el-icon-delete"
-                               @click="del(s.row)">删除
-                    </el-button>
-                </template>
-            </el-table-column>
-        </el-table>
-        <!-- ------------- 分页 ------------- -->
-        <sa-item type="page" :curr.sync="p.pageNo" :size.sync="p.pageSize" :total="dataCount" @change="f5()"></sa-item>
-    </div>
-    <el-dialog title="申请开票" :visible.sync="applyDate.visible" width="38%">
-        <sa-item name="发票总额" v-model="applyDate.form.totalMoney" type="num" :disabled="true"></sa-item>
-        <sa-item name="开票种类" v-model="applyDate.form.isElec" type="enum"
-                 :jv="{1: '电子普票', 0: '纸质普票', 2:'纸质专票'}"></sa-item>
-        <div class="c-item">
-            <label class="c-label">开票主体:</label>
-            <el-select v-model="applyDate.form.entityId" placeholder="请选择" filterable @change="changeEntity">
-                <el-option v-for="item in entityList" :key="item.id"
-                           :label="item.name" :value="item.id">
-                </el-option>
-            </el-select>
-        </div>
-        <sa-item type="text" name="企业名称" v-model="applyDate.entity.name" :disabled="true"></sa-item>
-        <sa-item type="text" name="税号" v-model="applyDate.entity.taxIdNo" :disabled="true"></sa-item>
-        <sa-item type="text" name="地址" v-model="applyDate.entity.address" :disabled="true"></sa-item>
-        <sa-item type="text" name="电话" v-model="applyDate.entity.phone" :disabled="true"></sa-item>
-        <sa-item type="text" name="开户银行" v-model="applyDate.entity.bank" :disabled="true"></sa-item>
-        <sa-item type="text" name="银行账号" v-model="applyDate.entity.bankNo" :disabled="true"></sa-item>
-        <span slot="footer" class="dialog-footer">
+					<sa-td name="业务名称" prop="businessName" width="150px" ></sa-td>
+					<sa-td name="车牌号" prop="carNo" width="150px"></sa-td>
+					<el-table-column label="业务订单号" width="150px">
+						<template slot-scope="s">
+							<el-tooltip :content="s.row.businessNo"placement="bottom"effect="light">
+								<el-button class="keyButton">{{ s.row.businessNo }}</el-button>
+							</el-tooltip>
+						</template>
+					</el-table-column>
+<!--					<sa-td name="业务订单号" prop="businessNo" width="150" ></sa-td>-->
+
+					<sa-td name="微信支付订单号" prop="transactionId" width="210px"></sa-td>
+					<sa-td name="账单金额" prop="billMoney" ></sa-td>
+					<sa-td name="账单截图" prop="billImage" type="img"></sa-td>
+					<sa-td name="开票状态" prop="status" type="enum" :jv="{0: '待申请', 1: '已申请', 2: '已开票'}"></sa-td>
+					<sa-td name="开票时间" prop="invoiceTime" width="100px"></sa-td>
+					<sa-td name="开票信息" prop="infoNo" width="130"></sa-td>
+					<el-table-column label="操作" fixed="right"  width="240px">
+						<template slot-scope="s">
+							<el-button class="c-btn" type="success" icon="el-icon-view" @click="get(s.row)">查看</el-button>
+							<el-button v-if="s.row.status==0" class="c-btn" type="danger" icon="el-icon-delete" @click="del(s.row)">删除</el-button>
+						</template>
+					</el-table-column>
+				</el-table>
+				<!-- ------------- 分页 ------------- -->
+				<sa-item type="page" :curr.sync="p.pageNo" :size.sync="p.pageSize" :total="dataCount" @change="f5()"></sa-item>
+			</div>
+			<el-dialog title="申请开票" :visible.sync="applyDate.visible" width="38%">
+				<sa-item name="发票总额" v-model="applyDate.form.totalMoney" type="num" :disabled="true"></sa-item>
+				<sa-item name="开票种类" v-model="applyDate.form.isElec" type="enum" :jv="{1: '电子普票', 0: '纸质普票', 2:'纸质专票'}"></sa-item>
+				<div class="c-item">
+					<label class="c-label">开票主体:</label>
+					<el-select v-model="applyDate.form.entityId" placeholder="请选择" filterable @change="changeEntity">
+						<el-option v-for="item in entityList" :key="item.id"
+								   :label="item.name" :value="item.id">
+						</el-option>
+					</el-select>
+				</div>
+				<sa-item type="text" name="企业名称" v-model="applyDate.entity.name":disabled="true"></sa-item>
+				<sa-item type="text" name="税号" v-model="applyDate.entity.taxIdNo" :disabled="true"></sa-item>
+				<sa-item type="text" name="地址" v-model="applyDate.entity.address" :disabled="true"></sa-item>
+				<sa-item type="text" name="电话" v-model="applyDate.entity.phone" :disabled="true"></sa-item>
+				<sa-item type="text" name="开户银行" v-model="applyDate.entity.bank" :disabled="true"></sa-item>
+				<sa-item type="text" name="银行账号" v-model="applyDate.entity.bankNo" :disabled="true"></sa-item>
+				<span slot="footer" class="dialog-footer">
 					<el-button @click="applyDate.visible = false">取 消</el-button>
 					<el-button type="primary" @click="apply">确 定</el-button>
 				</span>
-    </el-dialog>
-</div>
-<script>
-    var app = new Vue({
-        components: {
-            "sa-item": httpVueLoader('../../sa-frame/com/sa-item.vue'),
-            "sa-td": httpVueLoader('../../sa-frame/com/sa-td.vue'),
-        },
-        el: '.vue-box',
-        data: {
-            p: { // 查询参数
-                id: '',		// 主键 、
+			</el-dialog>
+		</div>
+		<script>
+			var app = new Vue({
+				components: {
+					"sa-item": httpVueLoader('../../sa-frame/com/sa-item.vue'),  
+					"sa-td": httpVueLoader('../../sa-frame/com/sa-td.vue'),		
+				},
+				el: '.vue-box',
+				data: {
+					p: { // 查询参数  
+						id: '',		// 主键 、
 
-                customerId: '',		// 客户id
-                businessId: '',		// 业务订单id
-                businessName: '',		// 业务名称
-                businessNo: '',		// 业务订单号
-                carNo: '',         //车牌号
-                transactionId: '',		// 微信支付订单号
-                billMoney: '',		// 账单金额
-                status: '',		// 支付状态(0=未开票,1=已开票)
-                invoiceTime: '',		// 开票时间
-                createTime: '',		// 创建时间
-                infoId: '',		// 开票信息id
-                infoNo: '',     // 开票信息no
-                pageNo: 1,		// 当前页
-                pageSize: 10,	// 页大小
-                sortType: 0		// 排序方式
-            },
-            dataCount: 0,
-            dataList: [], // 数据集合
-            entityList: [],
-            applyDate: {
-                visible: false,
-                form: {
-                    ids: '',
-                    entityId: '',
-                    isElec: 1,
-                    totalMoney: 0,
-                    customerId: '',
-                    customerName: '',
-                },
-                entity: {},
-            },
-            currentCustomerId: '1',
-            currentCustomerName: '',
-        },
-        methods: {
-            apply() {
-                sa.checkNull(this.applyDate.form.entityId, '请选择 [主体信息]');
-                sa.checkNull(this.applyDate.form.isElec, '请选择 [电子发票]');
+						customerId: '',		// 客户id 
+						businessId: '',		// 业务订单id 
+						businessName: '',		// 业务名称 
+						businessNo: '',		// 业务订单号
+						carNo: '',         //车牌号
+						transactionId: '',		// 微信支付订单号 
+						billMoney: '',		// 账单金额 
+						status: '',		// 支付状态(0=未开票,1=已开票) 
+						invoiceTime: '',		// 开票时间 
+						createTime: '',		// 创建时间 
+						infoId: '',		// 开票信息id
+						infoNo: '',     // 开票信息no
+						pageNo: 1,		// 当前页 
+						pageSize: 10,	// 页大小 
+						sortType: 0		// 排序方式 
+					},
+					dataCount: 0,
+					dataList: [], // 数据集合
+					entityList: [],
+					applyDate: {
+						visible: false,
+						form: {
+							ids: '',
+							entityId: '',
+							isElec: 1,
+							totalMoney: 0,
+							customerId: '',
+							customerName: '',
+						},
+						entity:{},
+					},
+					currentCustomerId: '1',
+					currentCustomerName: '',
+				},
+				methods: {
+					apply(){
+						sa.checkNull(this.applyDate.form.entityId, '请选择 [主体信息]');
+						sa.checkNull(this.applyDate.form.isElec, '请选择 [电子发票]');
 
-                sa.ajax('/TbInvoiceInfo/generate', this.applyDate.form, function (res) {
+						sa.ajax('/TbInvoiceInfo/generate', this.applyDate.form, function(res){
 
-                    this.applyDate.visible = false;
-                    sa.alert('成功生成开票信息', this.f5);
-                }.bind(this));
-            },
-            applyFn() {
-                let selection = this.$refs['data-table'].selection;
-                if (selection.length == 0) {
-                    return sa.msg('请至少选择一条数据')
-                }
-                let ids = sa.getArrayField(selection, 'id');
-                for (var i = 0; i < selection.length; i++) {
-                    if (selection[i].status == 1 || selection[i].status == 2) {
-                        return sa.msg('请选择待申请的订单')
-                    }
-                }
-                let billMoneys = sa.getArrayField(selection, 'billMoney');
-                var totalMoney = 0;
-                for (var i = billMoneys.length - 1; i >= 0; i--) {
-                    totalMoney += billMoneys[i];
-                }
-                this.applyDate.form.totalMoney = totalMoney;
-                this.applyDate.visible = true;
-                this.applyDate.form.ids = ids.join(',');
-                this.getEntityList();
-            },
-            changeEntity(value) {
-                let entity = this.entityList.filter(obj => obj.id == value).pop();
-                this.applyDate.entity = entity;
-            },
-            getEntityList() {
-                sa.ajax('/TbEntity/getList', function (res) {
-                    this.entityList = res.data; // 数据
-                }.bind(this));
-            },
-            getCustomer() {
-                sa.ajax('/TbCostomer/getCurrentCustomer', function (resp) {
-                    this.currentCustomerId = resp.data.id;
-                    this.currentCustomerName = resp.data.name;
-                    this.applyDate.form.customerId = resp.data.id;
-                    this.applyDate.form.customerName = resp.data.name;
+							this.applyDate.visible = false;
+							sa.alert('成功生成开票信息',this.f5);
+						}.bind(this));
+					},
+					applyFn(){
+						let selection = this.$refs['data-table'].selection;
+						if(selection.length == 0) {
+							return sa.msg('请至少选择一条数据')
+						}
+						let ids = sa.getArrayField(selection, 'id');
+						for(var i=0; i<selection.length; i++){
+							if(selection[i].status == 1 || selection[i].status == 2){
+								return sa.msg('请选择待申请的订单')
+							}
+						}
+						let billMoneys = sa.getArrayField(selection, 'billMoney');
+						var totalMoney = 0;
+						for (var i=billMoneys.length-1; i>=0; i--) {
+							totalMoney += billMoneys[i];
+						}
+						this.applyDate.form.totalMoney = totalMoney;
+						this.applyDate.visible = true;
+						this.applyDate.form.ids = ids.join(',');
+						this.getEntityList();
+					},
+					changeEntity(value){
+						let entity = this.entityList.filter(obj => obj.id == value).pop();
+						this.applyDate.entity = entity;
+					},
+					getEntityList(){
+						sa.ajax('/TbEntity/getList', function(res) {
+							this.entityList = res.data; // 数据
+						}.bind(this));
+					},
+					getCustomer() {
+						sa.ajax('/TbCostomer/getCurrentCustomer', function(resp) {
+							this.currentCustomerId = resp.data.id;
+							this.currentCustomerName = resp.data.name;
+							this.applyDate.form.customerId = resp.data.id;
+							this.applyDate.form.customerName = resp.data.name;
 
-                }.bind(this));
-            },
-            // 刷新
-            f5: function () {
-                sa.ajax('/TbInvoiceOrder/getList', sa.removeNull(this.p), function (res) {
-                    this.dataList = res.data; // 数据
-                    this.dataCount = res.dataCount; // 数据总数
-                    sa.f5TableHeight();		// 刷新表格高度
-                }.bind(this));
-            },
-            // 查看
-            get: function (data) {
-                sa.showIframe('数据详情', 'tb-invoice-order-info.html?id=' + data.id, '1200px', '90%');
-            },
-            // 查看 - 根据选中的
-            getBySelect: function (data) {
-                var selection = this.$refs['data-table'].selection;
-                if (selection.length == 0) {
-                    return sa.msg('请选择一条数据')
-                }
-                this.get(selection[0]);
-            },
-            // 修改
-            update: function (data) {
-                sa.showIframe('修改数据', 'tb-invoice-order-add.html?id=' + data.id, '550px', '80%');
-            },
-            // 新增
-            add: function (data) {
-                sa.showIframe('新增数据', 'tb-invoice-order-add.html?id=-1&customerId=' + this.currentCustomerId, '550px', '60%');
-            },
-            // 删除
-            del: function (data) {
-                sa.confirm('是否删除,此操作不可撤销', function () {
-                    sa.ajax('/TbInvoiceOrder/delete?id=' + data.id, function (res) {
-                        sa.arrayDelete(this.dataList, data);
-                        sa.ok('删除成功');
-                        sa.f5TableHeight();		// 刷新表格高度
-                    }.bind(this))
-                }.bind(this));
-            },
-            // 批量删除
-            deleteByIds: function () {
-                // 获取选中元素的id列表
-                let selection = this.$refs['data-table'].selection;
-                let ids = sa.getArrayField(selection, 'id');
-                if (selection.length == 0) {
-                    return sa.msg('请至少选择一条数据')
-                }
-                // 提交删除
-                sa.confirm('是否批量删除选中数据?此操作不可撤销', function () {
-                    sa.ajax('/TbInvoiceOrder/deleteByIds', {ids: ids.join(',')}, function (res) {
-                        sa.arrayDelete(this.dataList, selection);
-                        sa.ok('删除成功');
-                        sa.f5TableHeight();		// 刷新表格高度
-                    }.bind(this))
-                }.bind(this));
-            },
-        },
-        created: function () {
-            this.f5();
-            this.getCustomer();
-            sa.onInputEnter();
-        }
-    })
-</script>
-</body>
+						}.bind(this));
+					},
+					// 刷新
+					f5: function() {
+						sa.ajax('/TbInvoiceOrder/getList', sa.removeNull(this.p), function(res) {
+							this.dataList = res.data; // 数据
+							this.dataCount = res.dataCount; // 数据总数 
+							sa.f5TableHeight();		// 刷新表格高度 
+						}.bind(this));
+					},
+					// 查看
+					get: function(data) {
+						sa.showIframe('数据详情', 'tb-invoice-order-info.html?id=' + data.id, '1200px', '90%');
+					},
+					// 查看 - 根据选中的
+					getBySelect: function(data) {
+						var selection = this.$refs['data-table'].selection;
+						if(selection.length == 0) {
+							return sa.msg('请选择一条数据')
+						}
+						this.get(selection[0]);
+					},
+					// 修改
+					update: function(data) {
+						sa.showIframe('修改数据', 'tb-invoice-order-add.html?id=' + data.id, '550px', '80%');
+					},
+					// 新增
+					add: function(data) {
+						sa.showIframe('新增数据', 'tb-invoice-order-add.html?id=-1&customerId=' + this.currentCustomerId, '550px', '60%');
+					},
+					// 删除
+					del: function(data) {
+						sa.confirm('是否删除,此操作不可撤销', function() {
+							sa.ajax('/TbInvoiceOrder/delete?id=' + data.id, function(res) {
+								sa.arrayDelete(this.dataList, data);
+								sa.ok('删除成功');
+								sa.f5TableHeight();		// 刷新表格高度 
+							}.bind(this))
+						}.bind(this));
+					},
+					// 批量删除
+					deleteByIds: function() {
+						// 获取选中元素的id列表 
+						let selection = this.$refs['data-table'].selection;
+						let ids = sa.getArrayField(selection, 'id');
+						if(selection.length == 0) {
+							return sa.msg('请至少选择一条数据')
+						}
+						// 提交删除 
+						sa.confirm('是否批量删除选中数据?此操作不可撤销', function() {
+							sa.ajax('/TbInvoiceOrder/deleteByIds', {ids: ids.join(',')}, function(res) {
+								sa.arrayDelete(this.dataList, selection);
+								sa.ok('删除成功');
+								sa.f5TableHeight();		// 刷新表格高度 
+							}.bind(this))
+						}.bind(this));
+					},
+				},
+				created: function() {
+					this.f5();
+					this.getCustomer();
+					sa.onInputEnter();
+				}
+			})
+		</script>
+	</body>
 </html>

+ 222 - 0
sp-server/src/main/java/com/pj/api/invoice/CallDomo.java

@@ -0,0 +1,222 @@
+package com.pj.api.invoice;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.MessageDigest;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @Description:
+ */
+public class CallDomo {
+
+    public static final String appid = "100001";
+    public static final String appsecret = "7214fefff0cf47d7950cb2fc3b5d670a";
+    public static final String requestUrl = "http://localhost:8090/api/vi/uim";
+
+    public static void main(String[] args) throws Exception {
+        Map<String, String> param = new HashMap<>();
+        param.put("action", "erpaysav");
+        param.put("appid", appid);
+        param.put("timestamp", date2StrByInt(new Date(), "yyyyMMddHHmmssFFF"));
+        param.put("transid", genTransId());
+        String sign = createSign(getSortedMap(param), appsecret);
+        param.put("sign", sign);
+        //拼装请求url
+        String url = getUrl(requestUrl, param);
+        // 请求接口对应的业务参数封装
+        JSONObject businessObj = new JSONObject();
+        String paramStr = "{" +
+                " \"appaysavx\":[" +
+                " {" +
+                " \"bnktyp\":\"CMB\"," +
+                " \"bustyp\":\"0\"," +
+                " \"ccynbr\":\"10\"," +
+                " \"cltacc\":\"000110100002\"," +
+                " \"cltnbr\":\"0003\"," +
+                " \"eptdat\":\"2021-07-04\"," +
+                " \"epttim\":\"11:01:00\"," +
+                " \"exttxOne\":\"摘要信息03\"," +
+                " \"oprmod\":\"3\"," +
+                " \"oprty\":\"202\"," +
+                " \"payson\":\"N\"," +
+                " \"paytyp\":\"2\"," +
+                " \"recnum\":1," +
+                " \"refnbp\":\"TEST20190704\"," +
+                " \"revacc\":\"8512384214654654\"," +
+                " \"revbnk\":\"招商银行科技园支行\"," +
+                " \"revcit\":\"深圳市\"," +
+                " \"revnam\":\"招商银行\"," +
+                " \"revprv\":\"广东省\"," +
+                " \"trsamt\":200," +
+                " \"trsuse\":\"摘要信息01\"" +
+                " }" +
+                " ]," +
+                " \"info\":{" +
+                " \"funName\":\"ERPAYSAV\"" +
+                " }" +
+                "}";
+        System.out.println(httppost(url, JSONObject.parseObject(paramStr)));
+    }
+
+    public static JSONObject httppost(String urlString, JSONObject obj) throws Exception {
+        PrintWriter out = null;
+        BufferedReader reader = null;
+        HttpURLConnection connection = null;
+        StringBuffer sb = new StringBuffer("");
+        if (null == obj) {
+            obj = new JSONObject();
+        }
+        try {// 创建连接
+            URL url = new URL(urlString);
+            URLConnection conn = url.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("Content-Type", "application/json");
+            // 设置发 送数据的格式
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            out = new PrintWriter(conn.getOutputStream());
+            out.print(obj.toString());
+            out.flush();
+            reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+            }
+            return JSONObject.parseObject(sb.toString());
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (reader != null) {
+                    reader.close();
+                }
+            } catch (IOException ex) {
+                System.out.println("调用in.close Exception, url=" + urlString + ex);
+            }
+        }
+        JSONObject jsonObj = new JSONObject();
+        jsonObj.put("code", "999");
+        jsonObj.put("msg", "请求服务(" + urlString + ")异常,请联系服务负责人");
+        return jsonObj;
+    }
+
+    /**
+     * 拼装请求URL
+     *
+     * @param basicUrl 基础url
+     * @param params   基础参数
+     * @return url
+     */
+    public static String getUrl(String basicUrl, Map<String, String> params) {
+        StringBuilder tmpUrl = new StringBuilder(basicUrl + "?");
+        for (String k : params.keySet()) {
+            tmpUrl.append(k).append("=").append(params.get(k)).append("&");
+        }
+        return tmpUrl.toString().substring(0, tmpUrl.length() - 1);
+    }
+
+    //获取随机流水号,流水号由调用方控制生成,如果使用同一流水号发//起请求视为重复调用
+    public static String genTransId() {
+        return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + (int) ((Math.random() * 9 + 1) * 100000);
+    }
+
+    /**
+     * 生成时间戳
+     *
+     * @return
+     */
+    public static String date2StrByInt(Date time, String par) {
+        SimpleDateFormat df = new SimpleDateFormat(par);
+        String date = "";
+        try {
+            if (time != null) {
+                date = df.format(time);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return date;
+    }
+
+    /**
+     * 生成sign
+     *
+     * @return
+     */
+    public static String createSign(SortedMap<String, String> params, String key) {
+        StringBuilder sb = new StringBuilder();
+        Set<Map.Entry<String, String>> es = params.entrySet();
+        Iterator<Map.Entry<String, String>> it = es.iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
+            String k = (String) entry.getKey();
+            String v = (String) entry.getValue();
+            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
+                sb.append(k + "=" + v + "&");
+            }
+        }
+        sb.append("key=").append(key);
+        String sign = MD5(sb.toString()).toUpperCase();
+        return sign;
+    }
+
+    /**
+     * 获取有序map
+     *
+     * @param map
+     * @return
+     */
+    public static SortedMap<String, String> getSortedMap(Map<String, String> map) {
+        SortedMap<String, String> sortedMap = new TreeMap<>();
+        Iterator<String> it = map.keySet().iterator();
+        while (it.hasNext()) {
+            String key = (String) it.next();
+            String value = map.get(key);
+            String temp = "";
+            if (null != value) {
+                temp = value.trim();
+            }
+            sortedMap.put(key, temp);
+        }
+        return sortedMap;
+    }
+
+    /**
+     * md5常用工具类
+     *
+     * @param data
+     * @return
+     */
+    public static String MD5(String data) {
+        try {
+            MessageDigest md5 = MessageDigest.getInstance("MD5");
+            byte[] array = md5.digest(data.getBytes("UTF-8"));
+            StringBuilder sb = new StringBuilder();
+            for (byte item : array) {
+                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+            }
+            return sb.toString().toUpperCase();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+}

+ 54 - 0
sp-server/src/main/java/com/pj/api/invoice/api/InvoiceApplyController.java

@@ -0,0 +1,54 @@
+package com.pj.api.invoice.api;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.pj.api.invoice.bo.InvoiceApplyCallBack;
+import com.pj.api.invoice.service.InvoiceApplyService;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.so.SoMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+/**
+
+ * @Auther: lzm
+ * @Date: 2022/08/11/2:59
+ * @Description:
+ */
+@RequestMapping("InvoiceApply")
+@RestController
+@Slf4j
+public class InvoiceApplyController {
+
+    @Resource
+    InvoiceApplyService invoiceApplyService;
+
+    @RequestMapping("applyInvoice")
+    public AjaxJson applyInvoice(){
+        SoMap so = SoMap.getRequestSoMap();
+        String infoId = so.getString("infoId");
+        String code = invoiceApplyService.applyInvoice(infoId);
+        if(StrUtil.equals("200", code)){
+            return AjaxJson.getSuccess();
+        }else{
+            return AjaxJson.getError();
+        }
+
+    }
+
+    @RequestMapping(value = "applyCallBack")
+    public Map<String, Object> applyCallBack(@RequestBody InvoiceApplyCallBack bo){
+        String sub = Base64.decodeStr(bo.getData());
+        log.info("计费系统开票申请回调:{}", JSONUtil.toJsonStr(bo));
+        log.info("回调明细:{}", sub);
+        Map<String, Object> result = invoiceApplyService.callBack(sub);
+        return result;
+    }
+
+}

+ 29 - 0
sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApply.java

@@ -0,0 +1,29 @@
+package com.pj.api.invoice.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @Auther: lzm
+ * @Date: 2022/08/09/10:37
+ * @Description:
+ */
+@Data
+@Accessors(chain = true)
+public class InvoiceApply implements Serializable {
+    /**时间戳*/
+    private String requestId;
+    /**对接不同系统来源 编码,用于区分不 同系统的回调接口*/
+    private String businessSystemCode;
+    /**接口业务编码*/
+    private String interfaceCode;
+
+    /**需要把data的值加 密成字符串,默认 为base64*/
+    private String data;
+
+
+
+}

+ 26 - 0
sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApplyCallBack.java

@@ -0,0 +1,26 @@
+package com.pj.api.invoice.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Auther: lzm
+ * @Date: 2022/08/10/15:15
+ * @Description:
+ */
+@Data
+@Accessors(chain = true)
+
+public class InvoiceApplyCallBack implements Serializable {
+
+    /**接口业务编码*/
+    private String interfaceCode;
+
+    /**需要把data的ase64解密*/
+    private String data;
+
+}

+ 110 - 0
sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApplyCallBackSub.java

@@ -0,0 +1,110 @@
+package com.pj.api.invoice.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Auther: lzm
+ * @Date: 2022/08/11/2:37
+ * @Description:
+ */
+@Data
+@Accessors(chain = true)
+public class InvoiceApplyCallBackSub implements Serializable {
+
+    /**单据编号*/
+    private String billNo;
+    /**批次号*/
+    private String batch;
+    /**作废原因*/
+    private String abolishReason;
+    /**购买方地址和电 话*/
+    private String buyerAddressAndTel;
+    /**购买方银行和账号*/
+    private String buyerBankAndAccount;
+    /**购买方名称*/
+    private String buyerName;
+    /**是 购买方性质*/
+    private Integer buyerProperty;
+    /**电子发票收票手机 号*/
+    private String buyerRecipientPhone;
+    /**购买方税号*/
+    private String buyerTaxpayerId;
+    /**作废人*/
+    private String canceler;
+    /**设备编号*/
+    private String deduction;
+    /**开票人*/
+    private String drawer;
+    /**收款人*/
+    private String payee;
+    /**复核人*/
+    private String reviewer;
+    /**价税合计*/
+    private String includeTaxAmount;
+    /**合计税额*/
+    private BigDecimal totalAmount;
+    /**含税标识,0-不含税,1-含 税*/
+    private Integer includeTaxFlag;
+    /**清单标志,0-非清单发票, 1-清单发票*/
+    private Integer inventoryMark;
+    /**发票代码*/
+    private String invoiceCode;
+    /**发票号码*/
+    private String invoiceNum;
+    /**发票状态 0-正常 2-待开 3- 红冲 6-作废*/
+    private String invoiceStatus;
+    /**开票日期*/
+    private String invoiceDate;
+
+    /**发票明细*/
+    private List<com.pj.api.invoice.bo.invoiceDetail> invoiceDetail;
+
+    /**PDF板式文件下载地址*/
+    private String invoiceFileUrl;
+    /**PDF转图片预览地址*/
+    private String invoiceImageUrl;
+    /**开票类型,0蓝票,1红票 【长度:1】*/
+    private String invoiceProperty;
+    /**发票种类*/
+    private String invoiceType;
+
+    /**发票种类*/
+    private String originalInvoiceCode;
+    /**发票种类*/
+    private String originalInvoiceNumber;
+    /**发票种类*/
+    private String printFlag;
+    /**发票种类*/
+    private String redInfoBillNo;
+    /**发票种类*/
+    private String remark;
+
+    private String sellerAddressAndTel;
+
+    private String sellerBankAndAccount;
+
+    private String sellerName;
+
+    private String sellerTaxpayerId;
+
+    private String serialNo;
+
+    private String systemSource;
+
+    private String taxedType;
+
+    private String terminalNo;
+
+
+
+
+
+
+}

+ 101 - 0
sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApplySub.java

@@ -0,0 +1,101 @@
+package com.pj.api.invoice.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * @Auther: lzm
+ */
+@Data
+@Accessors(chain = true)
+public class InvoiceApplySub implements Serializable {
+
+    /**单据编号*/
+    private String billNo;
+    /**支付类型*/
+    private String payType;
+    /**支付流水*/
+    private String transactionId;
+    /**组织编码*/
+    private String orgCode;
+    /**单据日期*/
+    private String billDate;
+    /**单据金额*/
+    private BigDecimal totalAmount;
+    /**自动开票*/
+    private Integer autoInvoice;
+    /**发票种类*/
+    private String invoiceType;
+    /**优先级*/
+    private String priority;
+    /**单据来源*/
+    private String billSource;
+    /**合同号*/
+    private String contractNo;
+    /**购买方名称*/
+    private String buyerName;
+    /**购买方税号*/
+    private String buyerTaxpayerId;
+    /**购买方银行和账号*/
+    private String buyerBankAndAccount;
+    /**购买方地址和电 话*/
+    private String buyerAddressAndTel;
+    /**电子发票收票手机 号*/
+    private String buyerRecipientPhone;
+    /**电子发票收票邮箱*/
+    private String buyerRecipientMail;
+    /**是 购买方性质*/
+    private Integer buyerProperty;
+    /** 销方税号*/
+    private String sellerTaxpayerId;
+    /**销方名称*/
+    private String sellerName;
+    /**销方银行和账号*/
+    private String sellerBankAndAccount;
+    /**销方地址和电话*/
+    private String sellerAddressAndTel;
+    /**含税标识*/
+    private Integer includeTaxFlag;
+    /**设备编号*/
+    private String deviceNo;
+    /**终端号码*/
+    private String terminalNo;
+    /**差额征税差额*/
+    private String deduction;
+    /**征税方式*/
+    private Integer taxationStyle;
+    /**开票人*/
+    private String drawer;
+    /**收款人*/
+    private String payee;
+    /**复核人*/
+    private String reviewer;
+    /**备注*/
+    private String remark;
+    /**自动合并*/
+    private Integer autoMerge;
+    /**匹配规则*/
+    private String pushMatchRules;
+    /**取值规则*/
+    private String fillValueRule;
+    /**主表扩展字段1*/
+    private String textField1;
+    /**主表扩展字段2*/
+    private String textField2;
+    /**主表扩展字段3*/
+    private String textField3;
+    /**主表扩展字段4*/
+    private String textField4;
+    /**主表扩展字段5*/
+    private String textField5;
+
+    /***/
+    private List<InvoiceApplySubDetail> billDetail;
+
+
+
+}

+ 68 - 0
sp-server/src/main/java/com/pj/api/invoice/bo/InvoiceApplySubDetail.java

@@ -0,0 +1,68 @@
+package com.pj.api.invoice.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Auther: lzm
+ * @Date: 2022/08/09/14:25
+ * @Description:
+ */
+@Data
+@Accessors(chain = true)
+public class InvoiceApplySubDetail implements Serializable {
+
+    /**明细金额*/
+    private BigDecimal amount;
+    /**明细金额*/
+    private String detailId;
+    /**商品编码*/
+    private String goodsCode;
+    /**商品名称*/
+    private String goodsName;
+    /**物料分类名称*/
+    private String materialType;
+    /**行性质,0整单折 扣,2正常商品行*/
+    private Integer lineProperty;
+    /**单价【长度: (14,8)】*/
+    private BigDecimal price;
+    /**享受优惠内容*/
+    private String privilegeContent;
+    /**是否享受优惠*/
+    private String privilegeFlag;
+    /**数量*/
+    private Integer quantity;
+    /**税收分类编码*/
+    private String revenueCode;
+    /**规格型号*/
+    private String specification;
+    /**税率*/
+    private String taxRate;
+    /**税额*/
+    private String taxAmount;
+    /**折扣金额*/
+    private String discountAmount;
+    /**折扣率*/
+    private String discountRate;
+    /**计量单位*/
+    private String units;
+    /**明细扩展字段1*/
+    private String extraField;
+    /**明细扩展字段1*/
+    private String extraField1;
+    /**明细扩展字段2*/
+    private String extraField2;
+    /**明细扩展字段3*/
+    private String extraField3;
+    /**明细扩展字段4*/
+    private String extraField4;
+    /**明细扩展字段5*/
+    private String extraField5;
+
+
+}

+ 60 - 0
sp-server/src/main/java/com/pj/api/invoice/bo/invoiceDetail.java

@@ -0,0 +1,60 @@
+package com.pj.api.invoice.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Auther: lzm
+ * @Date: 2022/08/11/2:51
+ * @Description:
+ */
+@Data
+@Accessors(chain = true)
+public class invoiceDetail implements Serializable {
+
+    /**明细金额*/
+    private BigDecimal amount;
+    /**业务系统明细id,用于反写 回原业务系统明细*/
+    private String billSourceId;
+
+    /**商品名称*/
+    private String goodsName;
+    /** 明细含税金额*/
+    private BigDecimal includeTaxAmount;
+    /** 明细含税单价*/
+    private BigDecimal includeTaxPrice;
+
+    /**行性质,0整单折 扣,2正常商品行*/
+    private Integer lineProperty;
+
+    /**享受优惠内容*/
+    private String privilegeContent;
+    /**是否享受优惠*/
+    private String privilegeFlag;
+    /**数量*/
+    private Integer quantity;
+    /**税收分类编码*/
+    private String revenueCode;
+    /**税收分类名称*/
+    private String revenueName;
+    /**明细序号*/
+    private String seq;
+    /**规格型号*/
+    private String specification;
+    /**税额*/
+    private BigDecimal taxAmount;
+    /**税率*/
+    private BigDecimal taxRate;
+
+    /**计量单位*/
+    private String units;
+    /**零税率标识*/
+    private String zeroTaxRateFlag;
+
+
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 22 - 0
sp-server/src/main/java/com/pj/api/invoice/bo/testbb.java


+ 20 - 0
sp-server/src/main/java/com/pj/api/invoice/demo.java

@@ -0,0 +1,20 @@
+package com.pj.api.invoice;
+
+import cn.hutool.core.date.DateUtil;
+
+import java.util.Date;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Auther: lzm
+ * @Date: 2022/08/08/18:17
+ * @Description:
+ */
+public class demo {
+
+    public static void main(String[] args) {
+        System.out.println(new Date().getTime());
+    }
+
+}

+ 260 - 0
sp-server/src/main/java/com/pj/api/invoice/service/InvoiceApplyService.java

@@ -0,0 +1,260 @@
+package com.pj.api.invoice.service;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Snowflake;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSON;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.pj.api.invoice.bo.InvoiceApply;
+import com.pj.api.invoice.bo.InvoiceApplyCallBackSub;
+import com.pj.api.invoice.bo.InvoiceApplySub;
+import com.pj.api.invoice.bo.InvoiceApplySubDetail;
+import com.pj.api.invoice.utils.InvoiceUtils;
+import com.pj.api.wx.bo.Attach;
+import com.pj.api.wx.bo.PriceBO;
+import com.pj.current.config.InvoiceConfig;
+import com.pj.project.tb_fee_details.TbFeeDetails;
+import com.pj.project.tb_fee_details.TbFeeDetailsService;
+import com.pj.project.tb_fee_statistics.TbFeeStatistics;
+import com.pj.project.tb_invoice_details.TbInvoiceDetails;
+import com.pj.project.tb_invoice_details.TbInvoiceDetailsService;
+import com.pj.project.tb_invoice_info.TbInvoiceInfo;
+import com.pj.project.tb_invoice_info.TbInvoiceInfoService;
+import com.pj.project.tb_invoice_info.dto.FeeDeatilsGroup;
+import com.pj.project.tb_invoice_order.TbInvoiceOrder;
+import com.pj.project.tb_invoice_order.TbInvoiceOrderService;
+import com.pj.project.tb_order.TbOrder;
+import com.pj.project.tb_order.TbOrderService;
+import com.pj.project4sp.global.BusinessException;
+import com.pj.utils.so.SoMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Auther: lzm
+ * @Date: 2022/08/09/14:51
+ * @Description:
+ */
+@Service
+@Transactional
+@Slf4j
+public class InvoiceApplyService {
+
+    @Resource
+    TbInvoiceDetailsService tbInvoiceDetailsService;
+    @Resource
+    TbInvoiceInfoService tbInvoiceInfoService;
+    @Resource
+    TbInvoiceOrderService tbInvoiceOrderService;
+    @Resource
+    TbFeeDetailsService tbFeeDetailsService;
+    @Resource
+    InvoiceConfig invoiceConfig;
+
+
+    private static final String appid = "5644763";
+    private static final String appsecret = "F382196D16B98BC6F4A461Ced7505953";
+    private static final String applyUrl = "http://117.141.148.233:8765/monolithic/uni/invoice/invoiceBillPush";
+    private static final String applyAction = "billPus";
+    private static final String businessTaxRateCode = "3040408000000000000";
+    private static final String carTaxRateCode = "3040502020200000000";
+    private static final String sellerTaxpayerId = "915003006188392540";
+    private static final String sellerName = "金蝶软件(中国)有限公司";
+
+    public String applyInvoice(String infoId){
+        String code = this.preApply(infoId);
+        if(!StrUtil.equals("200", code)) {
+            throw new BusinessException("开票申请推送失败!");
+        }
+        return code;
+    }
+
+
+    public String preApply(String infoId){
+        Date now = new Date();
+        Map<String, String> param = new HashMap<>();
+        param.put("action",invoiceConfig.getApplyAction());
+        param.put("appid", invoiceConfig.getAppId());
+        param.put("timestamp", InvoiceUtils.date2StrByInt(now, "yyyyMMddHHmmssFFF"));
+        param.put("transid", InvoiceUtils.genTransId());
+        String sign = InvoiceUtils.createSign(InvoiceUtils.getSortedMap(param), invoiceConfig.getAppSecret());
+        param.put("sign", sign);
+        //拼装请求url
+        String url = InvoiceUtils.getUrl(invoiceConfig.getApplyUrl(), param);
+
+        TbInvoiceInfo info = tbInvoiceInfoService.getById(infoId);
+        List<TbInvoiceDetails> invoiceDetails = tbInvoiceDetailsService.findByInfoId(infoId);
+
+
+        //开始组装接口参数
+        InvoiceApply invoiceApply = new InvoiceApply();
+        invoiceApply.setRequestId(now.getTime()+"")
+                .setBusinessSystemCode("SW_TEST")
+                .setInterfaceCode("BILL.PUSH");
+        List<InvoiceApplySub> applys = new ArrayList<>();
+        for (TbInvoiceDetails invoiceDetail : invoiceDetails) {
+            InvoiceApplySub apply = new InvoiceApplySub();
+            apply.setBillNo(invoiceDetail.getId()).setPayType("微信支付")
+                    .setBillDate(DateUtil.format(now, "yyyy-MM-dd"))
+                    .setTotalAmount(invoiceDetail.getMoney()).setIncludeTaxFlag(1)
+                    .setAutoInvoice(1).setAutoMerge(1)
+                    .setInvoiceType("026")
+                    .setBuyerName(info.getEntityName()).setBuyerTaxpayerId(info.getTaxIdNo())
+                    .setBuyerRecipientMail(info.getEmail())
+                    .setBuyerProperty(0)
+                    .setBuyerBankAndAccount(info.getBank()+info.getBankNo())
+                    .setTextField1(info.getCustomerName())
+                    .setSellerName(invoiceConfig.getSellerName())
+                    .setSellerTaxpayerId(invoiceConfig.getSellerTaxpayerId())
+                    .setTaxationStyle(0)
+                    .setDrawer(invoiceConfig.getDrawer())
+                    .setPayee(invoiceConfig.getPayee()).setReviewer(invoiceConfig.getReviewer());
+
+            //将所有开票订单的收费明细放在一个集合中,并对其分组
+            List<TbInvoiceOrder> orders = tbInvoiceOrderService.findByDetailId(invoiceDetail.getId());
+            List<FeeDeatilsGroup> feeDetailsGroupList = grouping(orders);
+
+            List<InvoiceApplySubDetail> applyDetails = new ArrayList<>();
+            Snowflake snowflake = IdUtil.getSnowflake(1, 1);
+            for (FeeDeatilsGroup group : feeDetailsGroupList) {
+                String detailId =  snowflake.nextIdStr();
+                InvoiceApplySubDetail applyDetail = new InvoiceApplySubDetail();
+                applyDetail.setAmount(group.getItemPrice())
+                        .setDetailId(detailId)
+                        .setGoodsName(group.getItemTypeName())
+                        .setLineProperty(2)
+                        .setQuantity(group.getNum())
+                        .setPrice(group.getUnitPrice())
+                        .setTaxRate(group.getTaxRate().toString());
+                if(StrUtil.equals("0.09", applyDetail.getTaxRate())){
+                    applyDetail.setRevenueCode(invoiceConfig.getCarTaxRateCode());
+                }else{
+                    applyDetail.setRevenueCode(invoiceConfig.getBusinessTaxRateCode());
+                }
+                applyDetails.add(applyDetail);
+            }
+            apply.setBillDetail(applyDetails);
+            applys.add(apply);
+        }
+
+        log.info("invoice apply url:" + url);
+
+        String applysJson = JSONUtil.toJsonStr(applys);
+        log.info("invoice apply data:" + applysJson);
+
+        String applysBase64 = Base64.encode(applysJson);
+        invoiceApply.setData(applysBase64);
+
+        String paramStr = JSONUtil.toJsonStr(invoiceApply);
+        log.info("invoice apply paramStr:" + paramStr);
+
+        String result = HttpUtil.createPost(url).header("Content-Type", "application/json").body(paramStr).execute().body();
+        log.info("invoice apply result:" + result);
+        JSONObject jsonResult = JSONUtil.parseObj(result);
+        if( StrUtil.equals("0", jsonResult.getStr("code"))){
+            info.setApplyAble(1);
+            tbInvoiceInfoService.updateById(info);
+            return "200";
+        }else {
+            return "500";
+        }
+    }
+
+
+    private List<FeeDeatilsGroup> grouping(List<TbInvoiceOrder> invoiceOrderList){
+        List<TbFeeDetails> feeDetailsList = new ArrayList<>();
+        for (TbInvoiceOrder invoiceOrder : invoiceOrderList) {
+            List<TbFeeDetails> detailsList = tbFeeDetailsService.findByTransactionId(invoiceOrder.getTransactionId());
+            feeDetailsList.addAll(detailsList);
+        }
+        List<FeeDeatilsGroup> list = new ArrayList<>();
+        for (TbFeeDetails detail : feeDetailsList) {
+            FeeDeatilsGroup group = new FeeDeatilsGroup();
+        BeanUtil.copyProperties(detail, group);
+        String hash = (detail.getItemTypeName() + detail.getUnitPrice()).hashCode() + "";
+        group.setGroupHash(hash);
+        list.add(group);
+    }
+        Map<String, List<FeeDeatilsGroup>> collect = list.stream()
+                .collect(Collectors.groupingBy(FeeDeatilsGroup::getGroupHash));
+        List<FeeDeatilsGroup> completeGroups = new ArrayList<>();
+        for (String key : collect.keySet()) {
+            List<FeeDeatilsGroup> partGroups = collect.get(key);
+            FeeDeatilsGroup realGroup = new FeeDeatilsGroup();
+            realGroup.setItemTypeName(partGroups.get(0).getItemTypeName())
+                    .setUnitPrice(partGroups.get(0).getUnitPrice())
+                    .setTaxRate(partGroups.get(0).getTaxRate());
+            for (FeeDeatilsGroup partGroup : partGroups) {
+                realGroup.setItemPrice(realGroup.getItemPrice().add(partGroup.getItemPrice()))
+                        .setNoTaxPrice(realGroup.getNoTaxPrice().add(partGroup.getNoTaxPrice()))
+                        .setTaxPrice(realGroup.getTaxPrice().add(partGroup.getTaxPrice()))
+                        .setNum(realGroup.getNum() + partGroup.getNum());
+            }
+            completeGroups.add(realGroup);
+        }
+        return completeGroups;
+    }
+
+
+    public synchronized Map<String, Object>  callBack(String sub) {
+        log.info("进入开票回调:");
+        Map<String, Object> map = new LinkedHashMap<>();
+
+        JSONObject jsonObject = JSONUtil.parseObj(sub);
+        InvoiceApplyCallBackSub callBackSub = JSONUtil.toBean(jsonObject, InvoiceApplyCallBackSub.class);
+
+        TbInvoiceDetails invoiceDetail = tbInvoiceDetailsService.getById(callBackSub.getBillNo());
+        if(invoiceDetail == null){
+            log.info("开票信息子记录{}不存在:", callBackSub.getBillNo());
+            map.put("code", 500);
+            map.put("message", "失败,开票信息数据异常");
+            return map;
+        }
+        if(invoiceDetail.getIsApply() == 2){
+            log.info("重复回调,开票信息子记录{}已开票成功:", callBackSub.getBillNo());
+        }else{
+            invoiceDetail.setIsApply(2).setInvoiceNo(callBackSub.getInvoiceNum()).setInvoiceCode(callBackSub.getInvoiceCode())
+                .setFileUrl(callBackSub.getInvoiceFileUrl()).setImageUrl(callBackSub.getInvoiceImageUrl());
+            tbInvoiceDetailsService.updateById(invoiceDetail);
+            TbInvoiceInfo info = tbInvoiceInfoService.getById(invoiceDetail.getInfoId());
+//            List<TbInvoiceDetails> infoAllDetails = tbInvoiceDetailsService.findByInfoId(info.getId());
+//            String newInvoiceNo = "";
+//            for (TbInvoiceDetails detail : infoAllDetails) {
+//                newInvoiceNo = StrUtil.isEmpty(newInvoiceNo) ?
+//                        detail.getInvoiceNo() : newInvoiceNo+","+detail.getInvoiceNo();
+//            }
+            info.setIsApply(2);
+            tbInvoiceInfoService.updateById(info);
+            String oldInvoiceNo = info.getInvoiceNo();
+            String newInvoiceNo = StrUtil.isEmpty(oldInvoiceNo) ?
+                    callBackSub.getInvoiceNum() : oldInvoiceNo+","+callBackSub.getInvoiceNum();
+
+            SoMap so = new SoMap();
+            so.put("id", info.getId());
+            so.put("invoiceTime", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+            so.put("invoiceNo", newInvoiceNo);
+            tbInvoiceInfoService.complete(so);
+
+        }
+        map.put("code", 200);
+        map.put("message", "成功");
+        return map;
+    }
+
+}

+ 181 - 0
sp-server/src/main/java/com/pj/api/invoice/utils/InvoiceUtils.java

@@ -0,0 +1,181 @@
+package com.pj.api.invoice.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.MessageDigest;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Auther: lzm
+ * @Date: 2022/08/09/16:04
+ * @Description:
+ */
+@Component
+@Slf4j
+public class InvoiceUtils {
+
+    /**
+     * 生成时间戳
+     *
+     * @return
+     */
+    public static String date2StrByInt(Date time, String par) {
+        SimpleDateFormat df = new SimpleDateFormat(par);
+        String date = "";
+        try {
+            if (time != null) {
+                date = df.format(time);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return date;
+    }
+
+    //获取随机流水号,流水号由调用方控制生成,如果使用同一流水号发//起请求视为重复调用
+    public static String genTransId() {
+        return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + (int) ((Math.random() * 9 + 1) * 100000);
+    }
+
+    /**
+     * 生成sign
+     *
+     * @return
+     */
+    public static String createSign(SortedMap<String, String> params, String key) {
+        StringBuilder sb = new StringBuilder();
+        Set<Map.Entry<String, String>> es = params.entrySet();
+        Iterator<Map.Entry<String, String>> it = es.iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
+            String k = (String) entry.getKey();
+            String v = (String) entry.getValue();
+            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
+                sb.append(k + "=" + v + "&");
+            }
+        }
+        sb.append("key=").append(key);
+        String sign = MD5(sb.toString()).toUpperCase();
+        return sign;
+    }
+
+    /**
+     * md5常用工具类
+     *
+     * @param data
+     * @return
+     */
+    public static String MD5(String data) {
+        try {
+            MessageDigest md5 = MessageDigest.getInstance("MD5");
+            byte[] array = md5.digest(data.getBytes("UTF-8"));
+            StringBuilder sb = new StringBuilder();
+            for (byte item : array) {
+                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+            }
+            return sb.toString().toUpperCase();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 获取有序map
+     *
+     * @param map
+     * @return
+     */
+    public static SortedMap<String, String> getSortedMap(Map<String, String> map) {
+        SortedMap<String, String> sortedMap = new TreeMap<>();
+        Iterator<String> it = map.keySet().iterator();
+        while (it.hasNext()) {
+            String key = (String) it.next();
+            String value = map.get(key);
+            String temp = "";
+            if (null != value) {
+                temp = value.trim();
+            }
+            sortedMap.put(key, temp);
+        }
+        return sortedMap;
+    }
+
+    /**
+     * 拼装请求URL
+     *
+     * @param basicUrl 基础url
+     * @param params   基础参数
+     * @return url
+     */
+    public static String getUrl(String basicUrl, Map<String, String> params) {
+        StringBuilder tmpUrl = new StringBuilder(basicUrl + "?");
+        for (String k : params.keySet()) {
+            tmpUrl.append(k).append("=").append(params.get(k)).append("&");
+        }
+        return tmpUrl.toString().substring(0, tmpUrl.length() - 1);
+    }
+
+    public static JSONObject httppost(String urlString, JSONObject obj) throws Exception {
+        PrintWriter out = null;
+        BufferedReader reader = null;
+        HttpURLConnection connection = null;
+        StringBuffer sb = new StringBuffer("");
+        if (null == obj) {
+            obj = new JSONObject();
+        }
+        try {// 创建连接
+            URL url = new URL(urlString);
+            URLConnection conn = url.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("Content-Type", "application/json");
+            // 设置发 送数据的格式
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            out = new PrintWriter(conn.getOutputStream());
+            out.print(obj.toString());
+            out.flush();
+            reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+            }
+            return JSONObject.parseObject(sb.toString());
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (reader != null) {
+                    reader.close();
+                }
+            } catch (IOException ex) {
+                System.out.println("调用in.close Exception, url=" + urlString + ex);
+    }
+}
+        JSONObject jsonObj = new JSONObject();
+        jsonObj.put("code", "999");
+        jsonObj.put("msg", "请求服务(" + urlString + ")异常,请联系服务负责人");
+        return jsonObj;
+    }
+
+}

+ 52 - 0
sp-server/src/main/java/com/pj/current/config/InvoiceConfig.java

@@ -0,0 +1,52 @@
+package com.pj.current.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Auther: lzm
+ * @Date: 2022/08/13/17:27
+ * @Description:
+ */
+@ConfigurationProperties(prefix = "invoice-config")
+@Component
+@Data
+public class InvoiceConfig {
+
+    private String appId;
+    private String appSecret;
+    private String applyUrl;
+    private String applyAction;
+    /**
+     * 业务税率编码
+     * */
+    private String businessTaxRateCode;
+    /**
+     * 停车税率编码
+     * */
+    private String carTaxRateCode;
+    /**
+     * 销售方税号
+     * */
+    private String sellerTaxpayerId;
+    /**
+     * 销售方名称
+     * */
+    private String sellerName;
+    /**
+     * 开票人
+     * */
+    private String drawer;
+    /**
+     * 收款人
+     * */
+    private String payee;
+    /**
+     * 复核人
+     * */
+    private String reviewer;
+
+}

+ 1 - 1
sp-server/src/main/java/com/pj/project/tb_business/TbBusinessService.java

@@ -382,7 +382,7 @@ public class TbBusinessService extends ServiceImpl<TbBusinessMapper, TbBusiness>
                                 .setPickCustomerName(tbCostomer.getName()).setPickTime(now)
                                 .setConfirm(1).setConfirmTime(now);
                         List<TbFeeDetails> feeDetailsList = tbFeeDetailsService.getByBusinessItemId(item.getId() + "");//重复交费会存在多个businessItemId
-                        if (feeDetailsList != null) {
+                        if(feeDetailsList!=null) {
                             for (TbFeeDetails feeDetails : feeDetailsList) {
                                 feeDetails.setPickCustomerName(item.getPickCustomerName());
                                 tbFeeDetailsService.updateById(feeDetails);

+ 10 - 10
sp-server/src/main/java/com/pj/project/tb_fee_details/TbFeeDetailsService.java

@@ -135,7 +135,7 @@ public class TbFeeDetailsService extends ServiceImpl<TbFeeDetailsMapper, TbFeeDe
         return tbFeeDetailsMapper.getList(so);
     }
 
-    public List<TbFeeDetails> getByBusinessItemId(String businessItemId) {
+    public TbFeeDetails getByBusinessItemId(String businessItemId) {
         QueryWrapper<TbFeeDetails> qw = new QueryWrapper<>();
         qw.lambda().eq(TbFeeDetails::getBusinessItemId,businessItemId);
         return list(qw);
@@ -335,8 +335,8 @@ public class TbFeeDetailsService extends ServiceImpl<TbFeeDetailsMapper, TbFeeDe
                 carNo = business.getChinaCarNo();
             }
             TbGoods businessCfg = tbGoodsService.getById(business.getGoodsId());
-            if ((TbGoods.LeaveEnum.BUSINESS_MONEY.getCode() == businessCfg.getChinaCarLeave() || TbGoods.LeaveEnum.APART_BUSINESS.getCode() == businessCfg.getChinaCarLeave())
-                    && TbGoods.LeaveEnum.BUSINESS_MONEY.getCode() != businessCfg.getVietnamCarLeave() && TbGoods.LeaveEnum.APART_BUSINESS.getCode() != businessCfg.getVietnamCarLeave()) {
+            if((TbGoods.LeaveEnum.BUSINESS_MONEY.getCode()==businessCfg.getChinaCarLeave() || TbGoods.LeaveEnum.APART_BUSINESS.getCode()==businessCfg.getChinaCarLeave())
+                    && TbGoods.LeaveEnum.BUSINESS_MONEY.getCode()!=businessCfg.getVietnamCarLeave() && TbGoods.LeaveEnum.APART_BUSINESS.getCode()!=businessCfg.getVietnamCarLeave()){
                 carNo = business.getChinaCarNo();
             }
             String businessCarIds = "";
@@ -344,13 +344,13 @@ public class TbFeeDetailsService extends ServiceImpl<TbFeeDetailsMapper, TbFeeDe
             List<RelationBusinessCar> relation = relationBusinessCarService.findByBusinessId(item.getBusinessId());
             for (RelationBusinessCar rela : relation) {
                 TbBusinessCar bt = tbBusinessCarService.getById(rela.getBusinessCarId());
-                if (StrUtil.contains(carNo, bt.getCarNo())) {
+                if(StrUtil.contains(carNo, bt.getCarNo())){
                     businessCarIds += bt.getId() + ",";
                     businessCarNos += bt.getNo() + ",";
                 }
             }
-            businessCarIds = StrUtil.sub(businessCarIds, 0, businessCarIds.length() - 1);
-            businessCarNos = StrUtil.sub(businessCarNos, 0, businessCarNos.length() - 1);
+            businessCarIds = StrUtil.sub(businessCarIds, 0, businessCarIds.length()-1);
+            businessCarNos = StrUtil.sub(businessCarNos, 0, businessCarNos.length()-1);
             businessFeeDetail.setBusinessId(item.getBusinessId()).setBusinessNo(business.getNo())
                     .setBusinessItemNo(item.getNo()).setBusinessCarId(businessCarIds).setBusinessCarNo(businessCarNos)
                     .setCarNo(carNo)
@@ -777,14 +777,14 @@ public class TbFeeDetailsService extends ServiceImpl<TbFeeDetailsMapper, TbFeeDe
             QueryWrapper<TbFeeDetails> ew2 = new QueryWrapper<>();
             ew2.like("create_time", day);
             Integer thisDayTotal = tbFeeDetailsMapper.selectCount(ew2);
-            if (confirmList.size() == thisDayTotal) {
+            if(confirmList.size() == thisDayTotal){
                 Set<String> names = new TreeSet<>();
                 for (TbFeeDetails detail : confirmList) {
-                    if (StrUtil.equals(personType, TbFeeDetails.personEnum.JICHA.getDesc())) {
+                    if(StrUtil.equals(personType, TbFeeDetails.personEnum.JICHA.getDesc())){
                         names.add(detail.getJiChaPerson());
-                    } else if (StrUtil.equals(personType, TbFeeDetails.personEnum.KAIDAN.getDesc())) {
+                    }else if(StrUtil.equals(personType, TbFeeDetails.personEnum.KAIDAN.getDesc())){
                         names.add(detail.getKaiDanPerson());
-                    } else {
+                    }else{
                         names.add(detail.getDiaoDuPerson());
                     }
                 }

+ 93 - 0
sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetails.java

@@ -0,0 +1,93 @@
+package com.pj.project.tb_invoice_details;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * Model: tb_invoice_details -- 开票详情表
+ * @author lzm 
+ */
+@Data
+@Accessors(chain = true)
+@TableName(TbInvoiceDetails.TABLE_NAME)
+@EqualsAndHashCode(callSuper = false)
+public class TbInvoiceDetails implements Serializable {
+
+	// ---------- 模块常量 ----------
+	/**
+	 * 序列化版本id 
+	 */
+	private static final long serialVersionUID = 1L;	
+	/**
+	 * 此模块对应的表名 
+	 */
+	public static final String TABLE_NAME = "tb_invoice_details";	
+	/**
+	 * 此模块对应的权限码 
+	 */
+	public static final String PERMISSION_CODE = "tb-invoice-details-list";
+
+
+	// ---------- 表中字段 ----------
+	/**
+	 * 主键 
+	 */
+	private String id;
+
+    private String no;
+
+	/**
+	 * 开票信息id 
+	 */
+    private String infoId;
+
+	/**
+	 * 账单金额 
+	 */
+    private BigDecimal money;
+
+	/**
+	 * 主体名称 
+	 */
+    private String entityName;
+
+    /**
+     * 发票号
+     */
+    private String invoiceNo;
+
+    /**
+     * 发票代码
+     */
+    private String invoiceCode;
+
+    /**
+     * 是否推送(0=未推送, 1=推送中, 2=推送且已回调)
+     */
+    private Integer isApply;
+
+    /**
+     * PDF板式文件下载地址
+     */
+    private String fileUrl;
+
+    /**
+     * PDF板式文件下载地址
+     */
+    private String imageUrl;
+
+
+
+
+
+
+
+	
+
+
+}

+ 121 - 0
sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetailsController.java

@@ -0,0 +1,121 @@
+package com.pj.project.tb_invoice_details;
+
+import java.util.List;
+
+import com.pj.project.tb_invoice_info.dto.FeeDeatilsGroup;
+import com.pj.utils.so.SoMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import com.pj.utils.sg.*;
+import com.pj.project4sp.SP;
+
+import com.pj.current.satoken.StpUserUtil;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+
+
+/**
+ * Controller: tb_invoice_details -- 开票详情表
+ * @author lzm 
+ */
+@RestController
+@RequestMapping("/TbInvoiceDetails/")
+public class TbInvoiceDetailsController {
+
+	/** 底层 Service 对象 */
+	@Autowired
+	TbInvoiceDetailsService tbInvoiceDetailsService;
+
+	/** 增 */  
+	@RequestMapping("add")
+	@Transactional(rollbackFor = Exception.class)
+	public AjaxJson add(TbInvoiceDetails t){
+		tbInvoiceDetailsService.add(t);
+		t = tbInvoiceDetailsService.getById(SP.publicMapper.getPrimarykey());
+		return AjaxJson.getSuccessData(t);
+	}
+
+	/** 删 */  
+	@RequestMapping("delete")
+	public AjaxJson delete(String id){
+		int line = tbInvoiceDetailsService.delete(id);
+		return AjaxJson.getByLine(line);
+	}
+	
+	/** 删 - 根据id列表 */  
+	@RequestMapping("deleteByIds")
+	public AjaxJson deleteByIds(){
+		List<Long> ids = SoMap.getRequestSoMap().getListByComma("ids", long.class); 
+		int line = SP.publicMapper.deleteByIds(TbInvoiceDetails.TABLE_NAME, ids);
+		return AjaxJson.getByLine(line);
+	}
+	
+	/** 改 */  
+	@RequestMapping("update")
+	public AjaxJson update(TbInvoiceDetails t){
+		int line = tbInvoiceDetailsService.update(t);
+		return AjaxJson.getByLine(line);
+	}
+
+	/** 查 - 根据id */  
+	@RequestMapping("getById")
+	public AjaxJson getById(Long id){
+		TbInvoiceDetails t = tbInvoiceDetailsService.getById(id);
+		return AjaxJson.getSuccessData(t);
+	}
+
+	/** 查集合 - 根据条件(参数为空时代表忽略指定条件) */  
+	@RequestMapping("getList")
+	public AjaxJson getList() { 
+		SoMap so = SoMap.getRequestSoMap();
+		List<TbInvoiceDetails> list = tbInvoiceDetailsService.getList(so.startPage());
+		return AjaxJson.getPageData(so.getDataCount(), list);
+	}
+
+    @RequestMapping("onlineInvoice")
+    public AjaxJson onlineInvoice(String infoId) {
+        List<TbInvoiceDetails> list = tbInvoiceDetailsService.findByInfoId(infoId);
+        if(list.size() == 0){
+            tbInvoiceDetailsService.addInvioceDetails(infoId);
+            list = tbInvoiceDetailsService.findByInfoId(infoId);
+        }
+        return AjaxJson.getSuccessData(list);
+    }
+
+//    @RequestMapping("applyInvoice")
+//    public AjaxJson applyInvoice(String infoId){
+//        tbInvoiceDetailsService.applyInvoice(infoId);
+//	    return AjaxJson.getSuccess();
+//    }
+
+    @RequestMapping("groupFeeDetails")
+    public AjaxJson groupFeeDetails(String id){
+        List<FeeDeatilsGroup> feeDeatilsGroups =  tbInvoiceDetailsService.groupFeeDetails(id);
+        return AjaxJson.getSuccessData(feeDeatilsGroups);
+    }
+	
+	// ------------------------- 前端接口 -------------------------
+	
+	
+	/** 改 - 不传不改 [G] */
+	@RequestMapping("updateByNotNull")
+	public AjaxJson updateByNotNull(Long id){
+		AjaxError.throwBy(true, "如需正常调用此接口,请删除此行代码");
+		// 鉴别身份,是否为数据创建者 
+		long userId = SP.publicMapper.getColumnByIdToLong(TbInvoiceDetails.TABLE_NAME, "user_id", id);
+		AjaxError.throwBy(userId != StpUserUtil.getLoginIdAsLong(), "此数据您无权限修改");
+		// 开始修改 (请只保留需要修改的字段)
+		SoMap so = SoMap.getRequestSoMap();
+		so.clearNotIn("id", "infoId", "money", "entityName").clearNull().humpToLineCase();	
+		int line = SP.publicMapper.updateBySoMapById(TbInvoiceDetails.TABLE_NAME, so, id);
+		return AjaxJson.getByLine(line);
+	}
+	
+	
+	
+	
+	
+	
+
+}

+ 56 - 0
sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetailsMapper.java

@@ -0,0 +1,56 @@
+package com.pj.project.tb_invoice_details;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+import com.pj.utils.so.*;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Mapper: tb_invoice_details -- 开票详情表
+ * @author lzm 
+ */
+
+@Mapper
+@Repository
+public interface TbInvoiceDetailsMapper extends BaseMapper<TbInvoiceDetails> {
+
+	/**
+	 * 增  
+	 * @param t 实体对象 
+	 * @return 受影响行数 
+	 */
+	int add(TbInvoiceDetails t);
+
+	/**
+	 * 删  
+	 * @param id 要删除的数据id  
+	 * @return 受影响行数 
+	 */
+	int delete(String id);
+
+	/** 
+	 * 改  
+	 * @param t 实体对象 
+	 * @return 受影响行数 
+	 */
+	int update(TbInvoiceDetails t);
+
+	/** 
+	 * 查 - 根据id  
+	 * @param id 要查询的数据id 
+	 * @return 实体对象 
+	 */
+	TbInvoiceDetails getById(Long id);	 
+
+	/**
+	 * 查集合 - 根据条件(参数为空时代表忽略指定条件)
+	 * @param so 参数集合 
+	 * @return 数据列表 
+	 */
+	List<TbInvoiceDetails> getList(SoMap so);
+
+
+}

+ 80 - 0
sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetailsMapper.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pj.project.tb_invoice_details.TbInvoiceDetailsMapper">
+
+	<!-- 增 [G] -->
+	<insert id="add">
+		insert into 
+		tb_invoice_details (id, info_id, money, entity_name) 
+		values (#{id}, #{infoId}, #{money}, #{entityName}) 
+	</insert>
+
+	<!-- 删 -->
+	<delete id="delete">
+		delete from tb_invoice_details 
+		where id = #{id}
+	</delete>
+
+	<!-- 改 [G] -->
+	<update id="update">
+		update tb_invoice_details set
+		id = #{id}, 
+		info_id = #{infoId}, 
+		money = #{money}, 
+		entity_name = #{entityName}
+		where id = #{id}
+	</update>
+
+
+	<!-- ================================== 查询相关 ================================== -->
+	<!-- select id, info_id, money, entity_name from tb_invoice_details  -->
+	
+	<!-- 通用映射:手动模式 -->
+	<resultMap id="model" type="com.pj.project.tb_invoice_details.TbInvoiceDetails">
+		<result property="id" column="id" />
+		<result property="infoId" column="info_id" />
+		<result property="money" column="money" />
+		<result property="entityName" column="entity_name" />
+	</resultMap>
+	
+	<!-- 公共查询sql片段 -->
+	<sql id="select_sql">
+		select * 
+		from tb_invoice_details 
+	</sql>
+	
+	<!-- 查 - 根据id -->
+	<select id="getById" resultMap="model">
+		<include refid="select_sql"></include>
+		where id = #{id}
+	</select>
+	
+	<!-- 查集合 - 根据条件(参数为空时代表忽略指定条件) [G] -->
+	<select id="getList" resultMap="model">
+		<include refid="select_sql"></include>
+		<where>
+			<if test=' this.has("id") '> and id = #{id} </if>
+			<if test=' this.has("infoId") '> and info_id = #{infoId} </if>
+			<if test=' this.has("money") '> and money = #{money} </if>
+			<if test=' this.has("entityName") '> and entity_name = #{entityName} </if>
+		</where>
+		order by
+		<choose>
+			<when test='sortType == 1'> id desc </when>
+			<when test='sortType == 2'> info_id desc </when>
+			<when test='sortType == 3'> money desc </when>
+			<when test='sortType == 4'> entity_name desc </when>
+			<otherwise> id desc </otherwise>
+		</choose>
+	</select>
+	
+	
+	
+	
+	
+	
+	
+	
+	
+
+</mapper>

+ 172 - 0
sp-server/src/main/java/com/pj/project/tb_invoice_details/TbInvoiceDetailsService.java

@@ -0,0 +1,172 @@
+package com.pj.project.tb_invoice_details;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Snowflake;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.pj.api.invoice.service.InvoiceApplyService;
+import com.pj.project.tb_fee_details.TbFeeDetails;
+import com.pj.project.tb_fee_details.TbFeeDetailsService;
+import com.pj.project.tb_invoice_info.TbInvoiceInfo;
+import com.pj.project.tb_invoice_info.TbInvoiceInfoService;
+import com.pj.project.tb_invoice_info.dto.FeeDeatilsGroup;
+import com.pj.project.tb_invoice_order.TbInvoiceOrder;
+import com.pj.project.tb_invoice_order.TbInvoiceOrderService;
+import com.pj.project4sp.global.BusinessException;
+import com.pj.utils.so.SoMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.pj.utils.sg.*;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+
+/**
+ * Service: tb_invoice_details -- 开票详情表
+ * @author lzm 
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class TbInvoiceDetailsService extends ServiceImpl<TbInvoiceDetailsMapper, TbInvoiceDetails> implements IService<TbInvoiceDetails> {
+
+	/** 底层 Mapper 对象 */
+	@Resource
+	TbInvoiceDetailsMapper tbInvoiceDetailsMapper;
+    @Resource
+    TbInvoiceInfoService tbInvoiceInfoService;
+    @Resource
+    TbInvoiceOrderService tbInvoiceOrderService;
+    @Resource
+    InvoiceApplyService invoiceApplyService;
+    @Resource
+    TbFeeDetailsService tbFeeDetailsService;
+
+    private static final BigDecimal max_invoice_money = new BigDecimal(9999);
+
+	/** 增 */
+	int add(TbInvoiceDetails t){
+		return tbInvoiceDetailsMapper.add(t);
+	}
+
+	/** 删 */
+	public int delete(String id){
+		return tbInvoiceDetailsMapper.delete(id);
+	}
+
+	/** 改 */
+	int update(TbInvoiceDetails t){
+		return tbInvoiceDetailsMapper.update(t);
+	}
+
+	/** 查 */
+	TbInvoiceDetails getById(Long id){
+		return tbInvoiceDetailsMapper.getById(id);
+	}
+
+	/** 查集合 - 根据条件(参数为空时代表忽略指定条件) */  
+	List<TbInvoiceDetails> getList(SoMap so) {
+		return tbInvoiceDetailsMapper.getList(so);	
+	}
+
+    public List<TbInvoiceDetails> findByInfoId(String infoId) {
+        QueryWrapper<TbInvoiceDetails> ew = new QueryWrapper<>();
+        ew.eq("info_id", infoId);
+        return list(ew);
+    }
+
+    /** 根据开票信息创建开票信息明细,按开票最大金额9999元限制 拆分为多个开票信息明细 */
+    public void  addInvioceDetails(String infoId){
+        TbInvoiceInfo info = tbInvoiceInfoService.getById(infoId);
+
+        List<TbInvoiceOrder> orders = tbInvoiceOrderService.findByInfoId2(infoId);
+        Map<String, List<TbInvoiceOrder>> noMap = new LinkedHashMap<>();
+        List<TbInvoiceOrder> orderTempList = new ArrayList<>();
+        BigDecimal tempTotalMoney = new BigDecimal(0);
+        for (TbInvoiceOrder order : orders) {
+            tempTotalMoney = tempTotalMoney.add(order.getBillMoney());
+            if(tempTotalMoney.compareTo(max_invoice_money) <= 0){
+                //只要不达到9999,就把当前order加入orderTempList,作为同一张发票
+                orderTempList.add(order);
+            }else{
+                //只要达到9999,储存就把当前order加入orderTempList到map中,清空orderTempList,相当于另起一张发票
+                String no = DateUtil.format(new Date(), "yyyyMMddHHmmss") +  (int) ((Math.random() * 9 + 1) * 100000);
+                List<TbInvoiceOrder> invoiceDetails = new ArrayList<>();
+                invoiceDetails.addAll(orderTempList);
+                noMap.put(no, invoiceDetails);
+                orderTempList.clear();
+                tempTotalMoney = order.getBillMoney();
+                orderTempList.add(order);
+            }
+        }
+        String no = DateUtil.format(new Date(), "yyyyMMddHHmmss") +  (int) ((Math.random() * 9 + 1) * 100000);
+        noMap.put(no, orderTempList);
+        for (String key : noMap.keySet()) {
+            List<TbInvoiceOrder> thisOrders = noMap.get(key);
+            BigDecimal money = new BigDecimal(0);
+            for (TbInvoiceOrder order : thisOrders) {
+                money = money.add(order.getBillMoney());
+            }
+            TbInvoiceDetails invoiceDetail = new TbInvoiceDetails();
+            invoiceDetail.setNo(key).setEntityName(info.getEntityName()).setInfoId(infoId).setMoney(money).setIsApply(0);
+            this.save(invoiceDetail);
+            for (TbInvoiceOrder order : thisOrders) {
+                order.setDetailId(invoiceDetail.getId());
+            }
+            tbInvoiceOrderService.updateBatchById(thisOrders);
+        }
+        tbInvoiceInfoService.updateById(info);
+
+    }
+
+
+
+
+    public List<FeeDeatilsGroup> groupFeeDetails(String id) {
+        List<TbInvoiceOrder> orders = tbInvoiceOrderService.findByDetailId(id);
+        List<FeeDeatilsGroup> feeDetailsGroupList = grouping(orders);
+        return  feeDetailsGroupList;
+    }
+
+    private List<FeeDeatilsGroup> grouping(List<TbInvoiceOrder> invoiceOrderList){
+        List<TbFeeDetails> feeDetailsList = new ArrayList<>();
+        for (TbInvoiceOrder invoiceOrder : invoiceOrderList) {
+            List<TbFeeDetails> detailsList = tbFeeDetailsService.findByTransactionId(invoiceOrder.getTransactionId());
+            feeDetailsList.addAll(detailsList);
+        }
+        List<FeeDeatilsGroup> list = new ArrayList<>();
+        for (TbFeeDetails detail : feeDetailsList) {
+            FeeDeatilsGroup group = new FeeDeatilsGroup();
+            BeanUtil.copyProperties(detail, group);
+            String hash = (detail.getItemTypeName() + detail.getUnitPrice()).hashCode() + "";
+            group.setGroupHash(hash);
+            list.add(group);
+        }
+        Map<String, List<FeeDeatilsGroup>> collect = list.stream()
+                .collect(Collectors.groupingBy(FeeDeatilsGroup::getGroupHash));
+        List<FeeDeatilsGroup> completeGroups = new ArrayList<>();
+        for (String key : collect.keySet()) {
+            List<FeeDeatilsGroup> partGroups = collect.get(key);
+            FeeDeatilsGroup realGroup = new FeeDeatilsGroup();
+            realGroup.setItemTypeName(partGroups.get(0).getItemTypeName())
+                    .setUnitPrice(partGroups.get(0).getUnitPrice())
+                    .setTaxRate(partGroups.get(0).getTaxRate());
+            for (FeeDeatilsGroup partGroup : partGroups) {
+                realGroup.setItemPrice(realGroup.getItemPrice().add(partGroup.getItemPrice()))
+                        .setNoTaxPrice(realGroup.getNoTaxPrice().add(partGroup.getNoTaxPrice()))
+                        .setTaxPrice(realGroup.getTaxPrice().add(partGroup.getTaxPrice()))
+                        .setNum(realGroup.getNum() + partGroup.getNum());
+            }
+            completeGroups.add(realGroup);
+        }
+        return completeGroups;
+    }
+}

+ 10 - 0
sp-server/src/main/java/com/pj/project/tb_invoice_info/TbInvoiceInfo.java

@@ -131,6 +131,16 @@ public class TbInvoiceInfo implements Serializable {
      */
     private String email;
 
+    /**
+     * 是否推送(0=未申请,1=已申请,2=已开票) ,这里指是否调用计费系统的申请开票接口
+     */
+    private Integer isApply;
+
+    /**
+     * 能否申请开票(0=能,1=不能)
+     */
+    private Integer applyAble;
+
     @TableField(exist = false)
     private List<TbFeeDetails> feeDetails = new ArrayList<>();
 

+ 8 - 6
sp-server/src/main/java/com/pj/project/tb_invoice_info/TbInvoiceInfoService.java

@@ -13,6 +13,8 @@ import com.pj.project.tb_entity.TbEntity;
 import com.pj.project.tb_entity.TbEntityService;
 import com.pj.project.tb_fee_details.TbFeeDetails;
 import com.pj.project.tb_fee_details.TbFeeDetailsService;
+import com.pj.project.tb_invoice_details.TbInvoiceDetails;
+import com.pj.project.tb_invoice_details.TbInvoiceDetailsService;
 import com.pj.project.tb_invoice_info.dto.FeeDeatilsGroup;
 import com.pj.project.tb_invoice_order.TbInvoiceOrder;
 import com.pj.project.tb_invoice_order.TbInvoiceOrderService;
@@ -52,11 +54,7 @@ public class TbInvoiceInfoService extends ServiceImpl<TbInvoiceInfoMapper, TbInv
     @Resource
     TbFeeDetailsService tbFeeDetailsService;
     @Resource
-    SpAdminService spAdminService;
-    @Resource
-    WxService wxService;
-    @Resource
-    WxConfig wxConfig;
+    TbInvoiceDetailsService tbInvoiceDetailsService;
 
 
     /**
@@ -72,9 +70,13 @@ public class TbInvoiceInfoService extends ServiceImpl<TbInvoiceInfoMapper, TbInv
     int delete(Long id) {
         List<TbInvoiceOrder> iOrderList = tbInvoiceOrderService.findByInfoId(id + "");
         for (TbInvoiceOrder order : iOrderList) {
-            order.setInfoId("").setInfoNo("").setStatus(0);
+            order.setInfoId("").setInfoNo("").setStatus(0).setDetailId("");
         }
         tbInvoiceOrderService.updateBatchById(iOrderList);
+        List<TbInvoiceDetails> iDetailList = tbInvoiceDetailsService.findByInfoId(id + "");
+        for (TbInvoiceDetails detail : iDetailList) {
+            tbInvoiceDetailsService.delete(detail.getId());
+        }
         return tbInvoiceInfoMapper.delete(id);
     }
 

+ 82 - 72
sp-server/src/main/java/com/pj/project/tb_invoice_order/TbInvoiceOrder.java

@@ -1,18 +1,17 @@
 package com.pj.project.tb_invoice_order;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.Date;
-
 /**
  * Model: tb_invoice_order -- 开票订单表
- *
- * @author lzm
+ * @author lzm 
  */
 @Data
 @Accessors(chain = true)
@@ -20,94 +19,105 @@ import java.util.Date;
 @EqualsAndHashCode(callSuper = false)
 public class TbInvoiceOrder implements Serializable {
 
-    // ---------- 模块常量 ----------
-    /**
-     * 序列化版本id
-     */
-    private static final long serialVersionUID = 1L;
+	// ---------- 模块常量 ----------
+	/**
+	 * 序列化版本id 
+	 */
+	private static final long serialVersionUID = 1L;	
+	/**
+	 * 此模块对应的表名 
+	 */
+	public static final String TABLE_NAME = "tb_invoice_order";	
+	/**
+	 * 此模块对应的权限码 
+	 */
+	public static final String PERMISSION_CODE = "tb-invoice-order-list";
+
+
+	// ---------- 表中字段 ----------
+	/**
+	 * 主键 
+	 */
+	public String id;
+
+	/**
+	 * 客户id 
+	 */
+	public String customerId;
+
+	/**
+	 * 业务订单id 
+	 */
+	public String businessId;	
+
+	/**
+	 * 业务名称 
+	 */
+	public String businessName;	
+
+	/**
+	 * 业务订单号 
+	 */
+	public String businessNo;
+
     /**
-     * 此模块对应的表名
+     * 车牌号
      */
-    public static final String TABLE_NAME = "tb_invoice_order";
+    public String carNo;
     /**
-     * 此模块对应的权限码
-     */
-    public static final String PERMISSION_CODE = "tb-invoice-order-list";
+	 * 微信支付订单号 
+	 */
+	public String transactionId;	
 
+	/**
+	 * 账单金额 
+	 */
+	public BigDecimal billMoney;
 
-    // ---------- 表中字段 ----------
-    /**
-     * 主键
-     */
-    public String id;
+	/**
+	 * 账单截图 
+	 */
+	public String billImage;	
 
-    /**
-     * 客户id
-     */
-    public String customerId;
+	/**
+	 * 支付状态(0=未申请,1=已申请,2=已开票)
+	 */
+	public Integer status;
 
-    /**
-     * 业务订单id
-     */
-    public String businessId;
+	/**
+	 * 开票时间 
+	 */
+	public Date invoiceTime;
 
-    /**
-     * 业务名称
-     */
-    public String businessName;
+	/**
+	 * 创建时间 
+	 */
+	public Date createTime;
 
-    /**
-     * 业务订单号
-     */
-    public String businessNo;
+	/**
+	 * 开票信息id 
+	 */
+	public String infoId;
 
     /**
-     * 车牌号
-     */
-    public String carNo;
-    /**
-     * 微信支付订单号
+     * 开票信息id
      */
-    public String transactionId;
+    public String infoNo;
 
     /**
-     * 账单金额
+     * 预存款自动收费订单号
      */
-    public BigDecimal billMoney;
-
+    private String preOrderNum;
     /**
-     * 账单截图
+     * 开票信息明细Id
      */
-    public String billImage;
+    public String detailId;
+
 
-    /**
-     * 支付状态(0=未申请,1=已申请,2=已开票)
-     */
-    public Integer status;
 
-    /**
-     * 开票时间
-     */
-    public Date invoiceTime;
 
-    /**
-     * 创建时间
-     */
-    public Date createTime;
 
-    /**
-     * 开票信息id
-     */
-    public String infoId;
 
-    /**
-     * 开票信息id
-     */
-    public String infoNo;
 
-    /**
-     * 预存款自动收费订单号
-     */
-    private String preOrderNum;
 
 }

+ 47 - 28
sp-server/src/main/java/com/pj/project/tb_invoice_order/TbInvoiceOrderService.java

@@ -1,5 +1,14 @@
 package com.pj.project.tb_invoice_order;
 
+import java.io.File;
+import java.math.BigDecimal;
+import java.time.Month;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
 import cn.hutool.core.io.file.FileReader;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
@@ -15,6 +24,7 @@ import com.pj.project.tb_business.TbBusiness;
 import com.pj.project.tb_business.TbBusinessService;
 import com.pj.project.tb_business_car.TbBusinessCar;
 import com.pj.project.tb_business_car.TbBusinessCarService;
+import com.pj.project.tb_costomer.TbCostomer;
 import com.pj.project.tb_costomer.TbCostomerService;
 import com.pj.project.tb_fee_details.TbFeeDetails;
 import com.pj.project.tb_fee_details.TbFeeDetailsService;
@@ -107,14 +117,14 @@ public class TbInvoiceOrderService extends ServiceImpl<TbInvoiceOrderMapper, TbI
             for (TbBusiness tbBusiness : businessList) {
                 businessNoList.add(tbBusiness.getNo());
                 List<String> carNoList = new ArrayList<>();
-                if (StrUtil.isNotEmpty(tbBusiness.getCardNo())) {
+                if(StrUtil.isNotEmpty(tbBusiness.getCardNo())){
                     carNoList.addAll(StrUtil.split(tbBusiness.getCardNo(), "、"));
                 }
-                if (StrUtil.isNotEmpty(tbBusiness.getChinaCarNo())) {
+                if(StrUtil.isNotEmpty(tbBusiness.getChinaCarNo())){
                     carNoList.addAll(StrUtil.split(tbBusiness.getChinaCarNo(), "、"));
                 }
                 for (String no : carNoList) {
-                    if (!carNos.contains(no)) {
+                    if(!carNos.contains(no)){
                         carNos.add(no);
                     }
                 }
@@ -124,12 +134,12 @@ public class TbInvoiceOrderService extends ServiceImpl<TbInvoiceOrderMapper, TbI
             }
         }
         List<PriceBO> cars = JSONUtil.toList(attach.getC(), PriceBO.class);
-        if (cars.size() > 0) {
+        if(cars.size()>0){
             businessNameList.add("停车费");
             for (PriceBO bo1 : cars) {
                 TbBusinessCar car = tbBusinessCarService.getById(bo1.getId());
                 businessNoList.add(car.getNo());
-                if (!carNos.contains(car.getCarNo())) {
+                if(!carNos.contains(car.getCarNo())){
                     carNos.add(car.getCarNo());
                 }
             }
@@ -138,27 +148,25 @@ public class TbInvoiceOrderService extends ServiceImpl<TbInvoiceOrderMapper, TbI
         String businessNameStr = businessNameList.stream().map(String::valueOf).collect(Collectors.joining(","));
         String businessNoStr = businessNoList.stream().map(String::valueOf).collect(Collectors.joining(","));
         String carNoStr = carNos.stream().map(String::valueOf).collect(Collectors.joining(","));
-        t.setBusinessName(businessNameStr).setBusinessNo(businessNoStr).setCarNo(carNoStr)
+        t.setBusinessName(businessNameStr).setBusinessNo(businessNoStr).setCarNo(carNoStr).setStatus(1)
                 .setTransactionId(transactionId).setBillMoney(billMoney)
                 .setStatus(0).setCreateTime(new Date());
         tbInvoiceOrderMapper.add(t);
         return "200";
-    }
+	}
 
-    /**
-     * 增 --微信回调自动生成整车业务开票订单的情况
-     */
-    public void addT(String transactionId) {
+	/**增 --微信回调自动生成整车业务开票订单的情况*/
+	public void addT(String transactionId){
         TbInvoiceOrder t = new TbInvoiceOrder();
         TbInvoiceOrder InOrder = findByTransactionId(transactionId);
-        if (InOrder != null) {
+        if(InOrder != null){
             throw new BusinessException("该账单已生成开票订单");
         }
         List<String> businessNameList = new ArrayList<>();
         List<String> businessNoList = new ArrayList<>();
         List<String> carNos = new ArrayList<>();
         TbOrder tbOrder = tbOrderService.findByTransactionId(transactionId);
-        if (tbOrder == null) {
+        if(tbOrder == null){
             throw new BusinessException("交易单号识别有误,或不存在该交易单号的业务订单");
         }
         BigDecimal billMoney = new BigDecimal(tbOrder.getPrice());
@@ -173,14 +181,14 @@ public class TbInvoiceOrderService extends ServiceImpl<TbInvoiceOrderMapper, TbI
             for (TbBusiness tbBusiness : businessList) {
                 businessNoList.add(tbBusiness.getNo());
                 List<String> carNoList = new ArrayList<>();
-                if (StrUtil.isNotEmpty(tbBusiness.getCardNo())) {
+                if(StrUtil.isNotEmpty(tbBusiness.getCardNo())){
                     carNoList.addAll(StrUtil.split(tbBusiness.getCardNo(), "、"));
                 }
-                if (StrUtil.isNotEmpty(tbBusiness.getChinaCarNo())) {
+                if(StrUtil.isNotEmpty(tbBusiness.getChinaCarNo())){
                     carNoList.addAll(StrUtil.split(tbBusiness.getChinaCarNo(), "、"));
                 }
                 for (String no : carNoList) {
-                    if (!carNos.contains(no)) {
+                    if(!carNos.contains(no)){
                         carNos.add(no);
                     }
                 }
@@ -188,7 +196,7 @@ public class TbInvoiceOrderService extends ServiceImpl<TbInvoiceOrderMapper, TbI
                 TbGoods good = tbGoodsService.getById(tbBusiness.getGoodsId());
                 businessNameList.add(good.getName());
                 //微信回调的情况下,获取整车业务的客户id
-                if (!includZheng && StrUtil.contains(good.getName(), "整车")) {
+                if(!includZheng && StrUtil.contains(good.getName(), "整车")){
                     includZheng = true;
                     t.setCustomerId(tbBusiness.getCustomerId());
                 }
@@ -258,12 +266,17 @@ public class TbInvoiceOrderService extends ServiceImpl<TbInvoiceOrderMapper, TbI
         ew.eq("info_id", infoId);
         return list(ew);
     }
+    public List<TbInvoiceOrder> findByInfoId2(String infoId) {
+        QueryWrapper<TbInvoiceOrder> ew = new QueryWrapper<>();
+        ew.eq("info_id", infoId).orderByDesc("create_time");
+        return list(ew);
+    }
 
-    private String orcImage(String billImageUrl) {
+    private String orcImage(String billImageUrl){
         String separator = File.separator;
         int startIndex = StrUtil.lastIndexOf(billImageUrl, "/", billImageUrl.length(), false);
         int endIndex = StrUtil.lastIndexOf(billImageUrl, ".", billImageUrl.length(), false);
-        String picName = StrUtil.sub(billImageUrl, startIndex + 1, endIndex);
+        String picName =  StrUtil.sub(billImageUrl, startIndex+1, endIndex);
         String rootPath = UploadUtil.uploadConfig.rootFolder + separator + UploadUtil.uploadConfig.httpPrefix;
         String prefix = myConfig.getDomain() + UploadUtil.uploadConfig.httpPrefix;
         String path = billImageUrl.replaceAll(prefix, rootPath);
@@ -278,26 +291,25 @@ public class TbInvoiceOrderService extends ServiceImpl<TbInvoiceOrderMapper, TbI
 
     private static String getTransId(String content) {
         int index = StrUtil.indexOf(content, "420000", 0, false);
-        String sub = StrUtil.sub(content, index, index + 28);
-        sub = sub.trim();
+        String sub = StrUtil.sub(content, index, index+28);
+        sub=sub.trim();
         String transId = "";
-        for (int i = 0; i < sub.length(); i++) {
-            if (sub.charAt(i) >= 48 && sub.charAt(i) <= 57) {
+        for (int i=0; i<sub.length();i++){
+            if(sub.charAt(i)>=48 && sub.charAt(i)<=57){
                 transId += sub.charAt(i);
             }
         }
         log.info("transId:" + transId);
         return transId;
     }
-
     private static BigDecimal getMoney(String content) {
 
         int index = StrUtil.indexOf(content, ".", 0, false);
-        String sub = StrUtil.sub(content, index - 5, index + 3);
-        sub = sub.trim();
+        String sub = StrUtil.sub(content, index -5, index+3);
+        sub=sub.trim();
         String money = "";
-        for (int i = 0; i < sub.length(); i++) {
-            if (sub.charAt(i) >= 48 && sub.charAt(i) <= 57 || sub.charAt(i) == '.') {
+        for (int i=0; i<sub.length();i++){
+            if(sub.charAt(i)>=48 && sub.charAt(i)<=57 || sub.charAt(i) == '.'){
                 money += sub.charAt(i);
             }
         }
@@ -316,4 +328,11 @@ public class TbInvoiceOrderService extends ServiceImpl<TbInvoiceOrderMapper, TbI
                 .eq(TbFeeDetails::getPreOrderNum,preOrderNum));
         return detailsList;
     }
+    /**根据InvoiceDetail的id*/
+    public List<TbInvoiceOrder> findByDetailId(String detailId) {
+        QueryWrapper<TbInvoiceOrder> ew = new QueryWrapper<>();
+        ew.eq("detail_id", detailId);
+        return list(ew);
+    }
+
 }

+ 12 - 0
sp-server/src/main/resources/application-dev.yml

@@ -88,3 +88,15 @@ jh-config:
 ocr-config:
     bash: /opt/ocrpic/tesseract.sh
     analysis: /opt/ocrpic/ocrtxt/PIC_NAME.txt
+invoice-config:
+    app-id: 5644763
+    app-secret: F382196D16B98BC6F4A461Ced7505953
+    apply-url: http://117.141.148.233:8765/monolithic/uni/invoice/invoiceBillPush
+    apply-action: billPus
+    business-tax-rate-code: 3040408000000000000
+    car-tax-rate-code: 3040502020200000000
+    seller-taxpayer-id: 915003006188392540
+    seller-name: 金蝶软件(中国)有限公司
+    drawer: 白翠云
+    payee: 沈丕莹
+    reviewer: 沈丕莹

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.