wangqifan 4 years ago
parent
commit
00e49d820a

+ 34 - 0
src/main/java/com/izouma/zhumj/domain/BusinessPayment.java

@@ -0,0 +1,34 @@
+package com.izouma.zhumj.domain;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.BaseRowModel;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+@Data
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "应付账款", description = "应付账款")
+public class BusinessPayment extends BaseEntity {
+    private String     businessName;
+    private LocalDate  createdDate;
+    private String     contractNumber;
+    private String     contractName;
+    private String     projectStoreName;
+    private String     contractType;
+    private BigDecimal contractMoney;
+    private BigDecimal yesterYear;
+    private BigDecimal lastYear;
+    private BigDecimal thisYear;
+    private BigDecimal restMoney;
+    private String     name;
+}

+ 35 - 0
src/main/java/com/izouma/zhumj/domain/BusinessRent.java

@@ -0,0 +1,35 @@
+package com.izouma.zhumj.domain;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import java.math.BigDecimal;
+
+@Data
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "应付租金", description = "应付租金")
+public class BusinessRent extends BaseEntity {
+    @ApiModelProperty(value = "物业方")
+    private String     businessName;
+    @ApiModelProperty(value = "合同名称")
+    private String     contractName;
+    @ApiModelProperty(value = "项目门店")
+    private String     storeName;
+    @ApiModelProperty(value = "应付周期")
+    private String     cycle;
+    @ApiModelProperty(value = "总金额")
+    private BigDecimal money;
+    @ApiModelProperty(value = "已付金额")
+    private BigDecimal payed;
+    @ApiModelProperty(value = "剩余金额")
+    private BigDecimal rest;
+}

+ 36 - 0
src/main/java/com/izouma/zhumj/dto/excel/BusinessPaymentDTO.java

@@ -0,0 +1,36 @@
+package com.izouma.zhumj.dto.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.BaseRowModel;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "应收账款导入表", description = "应收账款导入表")
+public class BusinessPaymentDTO extends BaseRowModel {
+    @ExcelProperty(value = "供应商名称", index = 0)
+    private String businessName;
+    @ExcelProperty(value = "签订日期", index = 1)
+    private String createdDate;
+    @ExcelProperty(value = "合同号", index = 2)
+    private String contractNumber;
+    @ExcelProperty(value = "合同名称", index = 3)
+    private String contractName;
+    @ExcelProperty(value = "项目门店", index = 4)
+    private String projectStoreName;
+    @ExcelProperty(value = "合同类型", index = 5)
+    private String contractType;
+    @ExcelProperty(value = "合同金额", index = 6)
+    private String contractMoney;
+    @ExcelProperty(value = "2019年付款金额", index = 7)
+    private String yesterYear;
+    @ExcelProperty(value = "2020年付款金额", index = 8)
+    private String lastYear;
+    @ExcelProperty(value = "2021年付款金额", index = 9)
+    private String thisYear;
+    @ExcelProperty(value = "剩余金额", index = 10)
+    private String restMoney;
+    @ExcelProperty(value = "名字", index = 11)
+    private String name;
+
+}

+ 25 - 0
src/main/java/com/izouma/zhumj/dto/excel/BusinessRentDTO.java

@@ -0,0 +1,25 @@
+package com.izouma.zhumj.dto.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.BaseRowModel;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "应收账款导入表", description = "应收账款导入表")
+public class BusinessRentDTO extends BaseRowModel {
+    @ExcelProperty(value = "物业方", index = 0)
+    private String businessName;
+    @ExcelProperty(value = "合同名称", index = 1)
+    private String contractName;
+    @ExcelProperty(value = "项目门店", index = 2)
+    private String storeName;
+    @ExcelProperty(value = "应付周期", index = 3)
+    private String cycle;
+    @ExcelProperty(value = "应付金额", index = 4)
+    private String money;
+    @ExcelProperty(value = "已付金额", index = 5)
+    private String payed;
+    @ExcelProperty(value = "余额", index = 6)
+    private String rest;
+}

+ 2 - 0
src/main/java/com/izouma/zhumj/repo/CheckinInfoRepo.java

@@ -27,6 +27,8 @@ public interface CheckinInfoRepo extends JpaRepository<CheckinInfo, Long>, JpaSp
 
     List<CheckinInfo> findAllByIdNo(String idNo);
 
+    List<CheckinInfo> findAllByIdNoIn(List<String> idNos);
+
     List<CheckinInfo> findByDepositStatusAndIdIsNotIn(DepositStatus depositStatus, List<Long> ids);
 
     long countAllByOrderIdAndStoreIdAndCheckoutFalse(Long orderId, Long storeId);

+ 2 - 0
src/main/java/com/izouma/zhumj/repo/DepositRecordRepo.java

@@ -26,4 +26,6 @@ public interface DepositRecordRepo extends JpaRepository<DepositRecord, Long>, J
     List<DepositRecord> findShiftRefundDeposit(Long storeId, LocalDateTime start, LocalDateTime end);
 
     List<DepositRecord> findByCheckinInfoStoreIdAndCreatedAtBetween(Long storeId, LocalDateTime start, LocalDateTime end);
+
+    List<DepositRecord> findAllByCheckinInfoIdIn(List<Long> checkinInfos);
 }

+ 2 - 0
src/main/java/com/izouma/zhumj/repo/PersonalFeeRepo.java

@@ -32,6 +32,8 @@ public interface PersonalFeeRepo extends JpaRepository<PersonalFee, Long>, JpaSp
 
     List<PersonalFee> findByStoreIdAndSettleTimeBetweenAndEnabled(Long storeId, LocalDateTime start, LocalDateTime end, boolean enabled);
 
+    List<PersonalFee> findByStoreIdAndSettleTimeBetweenAndEnabledAndCheckinIdIn(Long storeId, LocalDateTime start, LocalDateTime end, boolean enabled, List<Long> checkinIds);
+
     List<PersonalFee> findByStoreIdAndPersonalFeeTypeIdAndSettleTimeBetween(Long storeId, Long id, LocalDateTime start, LocalDateTime end);
 
     List<PersonalFee> findByStoreIdAndPersonalFeeTypeNameAndSettleTimeBetween(Long storeId, String name, LocalDateTime start, LocalDateTime end);

+ 4 - 0
src/main/java/com/izouma/zhumj/repo/SuspendInfoRepo.java

@@ -4,5 +4,9 @@ import com.izouma.zhumj.domain.SuspendInfo;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 
+import java.time.LocalDateTime;
+import java.util.List;
+
 public interface SuspendInfoRepo extends JpaRepository<SuspendInfo, Long>, JpaSpecificationExecutor<SuspendInfo> {
+    List<SuspendInfo> findAllByStoreIdAndCreatedAtBetween(Long storeId, LocalDateTime start, LocalDateTime end);
 }

+ 105 - 0
src/main/java/com/izouma/zhumj/service/report/ReportService.java

@@ -76,6 +76,7 @@ public class ReportService {
     private final IndividualRentRepo  individualRentRepo;
     private final EntryRecordRepo     entryRecordRepo;
     private final StoreProxyFeeRepo   storeProxyFeeRepo;
+    private final SuspendInfoRepo     suspendInfoRepo;
 
     public List<DepositDetailDTO> allDepositDetail(Long storeId, LocalDateTime start, LocalDateTime end, DepositStatus depositStatus) {
         List<CheckinInfo> checkinInfoList = checkinInfoRepo
@@ -3041,4 +3042,108 @@ public class ReportService {
         });
         return storeIndividualReports;
     }
+
+    public List<List<String>> suspendFeeReport(LocalDate start, LocalDate end) {
+        List<List<String>> suspendFeeReport = Collections.synchronizedList(new ArrayList<>());
+        List<StoreInfo> storeInfos = storeInfoRepo.findAll();
+        storeInfos.removeIf(storeInfo -> !storeInfo.getStoreStatus().equals(StoreStatus.BUSINESS));
+        List<String> feeNames = feeNameRepo.findAll((Specification<FeeName>) (root, criteriaQuery, criteriaBuilder) ->
+                criteriaBuilder.notLike(root.get("name"), "%" + "押金" + "%")
+        ).stream().map(FeeName::getName).collect(Collectors.toList());
+        feeNames.add("押金");
+        feeNames.add("房费");
+        List<String> head = new ArrayList<>(Collections.singletonList("门店名称"));
+        head.addAll(feeNames);
+//        head.add("总收入");
+        suspendFeeReport.add(head);
+        storeInfos.stream().parallel().forEach(storeInfo -> {
+            List<String> list = Collections.synchronizedList(new ArrayList<>());
+            list.add(storeInfo.getStoreName());
+            BigDecimal total = BigDecimal.ZERO;
+            List<String> suspendIdNo = suspendInfoRepo
+                    .findAllByStoreIdAndCreatedAtBetween(storeInfo.getId(), start.atStartOfDay(), end
+                            .atTime(LocalTime.MAX)).stream().map(SuspendInfo::getIdNo).collect(Collectors.toList());
+            List<Long> checkinInfoList = checkinInfoRepo.findAllByIdNoIn(suspendIdNo).stream().map(CheckinInfo::getId)
+                    .collect(Collectors.toList());
+            List<PersonalFeeType> personalFeeTypes = personalFeeTypeRepo
+                    .findAll((Specification<PersonalFeeType>) (root, criteriaQuery, criteriaBuilder) ->
+                            criteriaQuery.where(
+                                    root.get("name").in(feeNames),
+                                    criteriaBuilder.equal(root.get("storeId"), storeInfo.getId())
+                            ).getRestriction());
+            //本门店的个人押金费用
+            List<PersonalFee> personalFees = personalFeeRepo
+                    .findByStoreIdAndSettleTimeBetweenAndEnabledAndCheckinIdIn(storeInfo.getId(), start
+                            .atStartOfDay(), end.atTime(23, 59, 59, 99), true, checkinInfoList);
+            for (String feeTypeName : feeNames) {
+                Set<Long> personalFeeTypeSet = personalFeeTypes.stream()
+                        .filter(personalFeeType -> personalFeeType.getName().equals(feeTypeName))
+                        .map(PersonalFeeType::getId).collect(Collectors.toSet());
+                BigDecimal fee = personalFees.stream()
+                        .filter(personalFee -> personalFeeTypeSet.stream().anyMatch(longVal ->
+                                longVal.equals(personalFee.getPersonalFeeTypeId())))
+                        .map(PersonalFee::getMoney).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
+                list.add(fee.toString());
+                total = total.add(fee);
+            }
+            list.add(depositRecordRepo.findAllByCheckinInfoIdIn(checkinInfoList).stream().map(DepositRecord::getRest)
+                    .reduce(BigDecimal::add).orElse(BigDecimal.ZERO).toString());
+            list.add(roomRateRepo.findAllByCheckinIdInAndDateBetween(checkinInfoList, start, end).stream()
+                    .map(RoomRate::getDayRate).reduce(BigDecimal::add).orElse(BigDecimal.ZERO).toString());
+            suspendFeeReport.add(list);
+        });
+        return suspendFeeReport;
+    }
+
+//    public List<List<String>> suspendFeeReport(LocalDate start, LocalDate end) {
+//        List<List<String>> suspendFeeReport = Collections.synchronizedList(new ArrayList<>());
+//        List<StoreInfo> storeInfos = storeInfoRepo.findAll();
+//        storeInfos.removeIf(storeInfo -> !storeInfo.getStoreStatus().equals(StoreStatus.BUSINESS));
+//        List<String> feeNames = feeNameRepo.findAll((Specification<FeeName>) (root, criteriaQuery, criteriaBuilder) ->
+//                criteriaBuilder.notLike(root.get("name"), "%" + "押金" + "%")
+//        ).stream().map(FeeName::getName).collect(Collectors.toList());
+//        feeNames.add("押金");
+//        feeNames.add("房费");
+//        List<String> head = new ArrayList<>(Collections.singletonList("门店名称"));
+//        head.addAll(feeNames);
+////        head.add("总收入");
+//        suspendFeeReport.add(head);
+//        storeInfos.stream().parallel().forEach(storeInfo -> {
+//            List<String> list = Collections.synchronizedList(new ArrayList<>());
+//            list.add(storeInfo.getStoreName());
+//            BigDecimal total = BigDecimal.ZERO;
+//            List<String> suspendIdNo = suspendInfoRepo
+//                    .findAllByStoreIdAndCreatedAtBetween(storeInfo.getId(), start.atStartOfDay(), end
+//                            .atTime(LocalTime.MAX)).stream().map(SuspendInfo::getIdNo).collect(Collectors.toList());
+//            List<Long> checkinInfoList = checkinInfoRepo.findAllByIdNoIn(suspendIdNo).stream().map(CheckinInfo::getId)
+//                    .collect(Collectors.toList());
+//            List<PersonalFeeType> personalFeeTypes = personalFeeTypeRepo
+//                    .findAll((Specification<PersonalFeeType>) (root, criteriaQuery, criteriaBuilder) ->
+//                            criteriaQuery.where(
+//                                    root.get("name").in(feeNames),
+//                                    criteriaBuilder.equal(root.get("storeId"), storeInfo.getId())
+//                            ).getRestriction());
+//            //本门店的个人押金费用
+//            List<PersonalFee> personalFees = personalFeeRepo
+//                    .findByStoreIdAndSettleTimeBetweenAndEnabledAndCheckinIdIn(storeInfo.getId(), start
+//                            .atStartOfDay(), end.atTime(23, 59, 59, 99), true, checkinInfoList);
+//            for (String feeTypeName : feeNames) {
+//                Set<Long> personalFeeTypeSet = personalFeeTypes.stream()
+//                        .filter(personalFeeType -> personalFeeType.getName().equals(feeTypeName))
+//                        .map(PersonalFeeType::getId).collect(Collectors.toSet());
+//                BigDecimal fee = personalFees.stream()
+//                        .filter(personalFee -> personalFeeTypeSet.stream().anyMatch(longVal ->
+//                                longVal.equals(personalFee.getPersonalFeeTypeId())))
+//                        .map(PersonalFee::getMoney).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
+//                list.add(fee.toString());
+//                total = total.add(fee);
+//            }
+//            list.add(depositRecordRepo.findAllByCheckinInfoIdIn(checkinInfoList).stream().map(DepositRecord::getRest)
+//                    .reduce(BigDecimal::add).orElse(BigDecimal.ZERO).toString());
+//            list.add(roomRateRepo.findAllByCheckinIdInAndDateBetween(checkinInfoList, start, end).stream()
+//                    .map(RoomRate::getDayRate).reduce(BigDecimal::add).orElse(BigDecimal.ZERO).toString());
+//            suspendFeeReport.add(list);
+//        });
+//        return suspendFeeReport;
+//    }
 }

+ 6 - 0
src/main/java/com/izouma/zhumj/web/report/ReportController.java

@@ -43,6 +43,7 @@ import org.springframework.data.domain.Pageable;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
+import javax.xml.stream.events.EndDocument;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.net.URLEncoder;
@@ -715,5 +716,10 @@ public class ReportController extends BaseController {
         ExcelUtils.export(response,
                 reportService.storeIndividualReport(storeId, roomId, search, checkinStatus));
     }
+
+    @GetMapping("/suspendFeeReport")
+    public List<List<String>> suspendFeeReport(@RequestParam LocalDate start, @RequestParam LocalDate end) {
+        return reportService.suspendFeeReport(start, end);
+    }
 }
 

+ 42 - 0
src/main/vue/src/router.js

@@ -1927,6 +1927,14 @@ const router = new Router({
                         title: '预算图表'
                     }
                 },
+                {
+                    path: '/suspendFeeReport',
+                    name: 'suspendFeeReport',
+                    component: () => import(/* webpackChunkName: "suspendFeeReport" */ '@/views/SuspendFeeReport.vue'),
+                    meta: {
+                        title: '门店挂账报表'
+                    }
+                },
                 {
                     path: '/roomFeeChart',
                     name: 'RoomFeeChart',
@@ -1935,6 +1943,40 @@ const router = new Router({
                     meta: {
                         title: '房费图表'
                     }
+                },
+                {
+                    path: '/businessPaymentEdit',
+                    name: 'BusinessPaymentEdit',
+                    component: () =>
+                        import(/* webpackChunkName: "businessPaymentEdit" */ '@/views/BusinessPaymentEdit.vue'),
+                    meta: {
+                        title: '应付账款编辑'
+                    }
+                },
+                {
+                    path: '/businessPaymentList',
+                    name: 'BusinessPaymentList',
+                    component: () =>
+                        import(/* webpackChunkName: "businessPaymentList" */ '@/views/BusinessPaymentList.vue'),
+                    meta: {
+                        title: '应付账款'
+                    }
+                },
+                {
+                    path: '/businessRentEdit',
+                    name: 'BusinessRentEdit',
+                    component: () => import(/* webpackChunkName: "businessRentEdit" */ '@/views/BusinessRentEdit.vue'),
+                    meta: {
+                        title: '应付租金编辑'
+                    }
+                },
+                {
+                    path: '/businessRentList',
+                    name: 'BusinessRentList',
+                    component: () => import(/* webpackChunkName: "businessRentList" */ '@/views/BusinessRentList.vue'),
+                    meta: {
+                        title: '应付租金'
+                    }
                 }
                 /**INSERT_LOCATION**/
             ]

+ 137 - 0
src/main/vue/src/views/SuspendFeeReport.vue

@@ -0,0 +1,137 @@
+<template>
+    <div class="list-view" v-loading="loading">
+        <div class="filters-container">
+            <el-date-picker
+                type="daterange"
+                value-format="yyyy-MM-dd"
+                v-model="range"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+            >
+            </el-date-picker>
+            <el-button @click="getData" type="primary" icon="el-icon-search" class="filter-item">查询 </el-button>
+            <el-button @click="exportExcel" :disabled="loading">导出EXCEL </el-button>
+        </div>
+        <el-table
+            :data="list"
+            row-key="id"
+            ref="table"
+            :height="tableHeight"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            show-summary
+            :summary-method="summaryMethod"
+        >
+            <el-table-column type="index" label="#" width="50" fixed="left"></el-table-column>
+            <el-table-column
+                v-for="(item, index) in head"
+                :label="item"
+                :prop="index + ''"
+                :key="index"
+                :width="index === 0 ? 200 : '110'"
+                :fixed="index === 0 ? 'left' : false"
+            ></el-table-column>
+        </el-table>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import format from 'date-fns/format';
+import addMonths from 'date-fns/addMonths';
+import XLSX from 'xlsx';
+export default {
+    name: 'suspendFeeReport',
+    created() {
+        let now = new Date();
+        this.range = [format(addMonths(now, -1), 'yyyy-MM-dd'), format(now, 'yyyy-MM-dd')];
+        this.getData();
+    },
+    mounted() {
+        this.tableHeight = document.querySelector('.el-table').getBoundingClientRect().height;
+    },
+    data() {
+        return {
+            tableHeight: 0,
+            search: '',
+            head: ['', '', ''],
+            list: [['', '', '']],
+            range: [],
+            loading: false
+        };
+    },
+    methods: {
+        getData() {
+            if (this.range && this.range[0] && this.range[1] && !this.loading) {
+                this.loading = true;
+                this.$http
+                    .get('/report/suspendFeeReport', {
+                        start: this.range[0],
+                        end: this.range[1]
+                    })
+                    .then(res => {
+                        this.loading = false;
+                        this.head = res[0];
+                        this.list = res.slice(1);
+                    })
+                    .catch(e => {
+                        this.loading = false;
+                    });
+            }
+        },
+        exportExcel() {
+            let workbook = XLSX.utils.book_new();
+            let sheet = XLSX.utils.aoa_to_sheet([this.head, ...this.list]);
+            XLSX.utils.book_append_sheet(workbook, sheet, '门店挂账报表');
+            XLSX.writeFile(workbook, '门店挂账报表.xlsx');
+        },
+        summaryMethod({ columns, data }) {
+            const sums = [];
+            columns.forEach((column, index) => {
+                if (index === 0) {
+                    sums[index] = '总计';
+                    return;
+                }
+                // if (column.label === '出租率' || column.label === '平均床价') {
+                //     sums[index] = '';
+                //     return;
+                // }
+                const values = data.map(item => Number(item[column.property]));
+                if (!values.every(value => isNaN(value))) {
+                    let sum = this.$math.bignumber(0);
+                    values.forEach(e => {
+                        sum = this.$math.add(sum, this.$math.bignumber(e));
+                    });
+                    sums[index] = sum.toString();
+                } else {
+                    sums[index] = 'N/A';
+                }
+            });
+
+            return sums;
+        }
+    },
+    watch: {
+        sort() {
+            let sortStr = [];
+            for (let [key, value] of Object.entries(this.sort)) {
+                if (value) {
+                    sortStr.push(key + ',' + value);
+                }
+            }
+            sortStr = sortStr.join(';');
+            this.$router
+                .replace({
+                    query: {
+                        ...this.$route.query,
+                        sort: sortStr
+                    }
+                })
+                .catch(_ => {});
+            this.sortStr = sortStr;
+            this.getData();
+        }
+    }
+};
+</script>