Jelajahi Sumber

feat(billing): 日/周/月账单接口增加 mdId 可选过滤参数

- getzddaylist、getzdmeeklist、getzdmatlist 增加 @RequestParam(required=false) Long mdId
- 对应 mapper SQL (getdaylist/getmeeklist/getmatlist 及 getdaysum/getmeeksum/getmatsum/getShDaysum/getShMeeksum/getshMonthsum) 增加 (#{mdId} IS NULL OR md_id = #{mdId}) 条件
- mdId 不传时行为不变,传入时按门店过滤

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
qmj 1 bulan lalu
induk
melakukan
e2aa07e678

+ 169 - 12
ruoyi-admin/src/main/java/com/ruoyi/app/pay/UserBillingController.java

@@ -68,6 +68,160 @@ public class UserBillingController extends BaseController {
     private IPosOrderRatingService posOrderRatingService;
     @Autowired
     private ICommissionRatesService commissionRatesService;
+    @Autowired
+    private IPosStoreService posStoreService;
+
+    /**
+     * 商家端账单列表
+     */
+    @Anonymous
+    @Auth
+    @GetMapping("/storeBillingList")
+    public AjaxResult storeBillingList(@RequestHeader String token,
+                                       @RequestParam Integer pageNum,
+                                       @RequestParam Integer pageSize,
+                                       @RequestParam(required = false) Long mdId,
+                                       @RequestParam(required = false) String type,
+                                       @RequestParam(required = false) String startDate,
+                                       @RequestParam(required = false) String endDate) {
+        JwtUtil jwtUtil = new JwtUtil();
+        Long userId = Long.valueOf(jwtUtil.getusid(token));
+        InfoUser user = infoUserService.getById(userId);
+        if (user == null) {
+            return error(MessageUtils.message("no.user.not.exist"));
+        }
+
+        QueryWrapper<UserBilling> wrapper = new QueryWrapper<>();
+        String userType = user.getUserType();
+
+        if ("1".equals(userType)) {
+            // 商家:查自己名下所有门店的账单
+            wrapper.eq("user_id", userId);
+            if (mdId != null) {
+                wrapper.eq("md_id", mdId);
+            }
+        } else if ("4".equals(userType)) {
+            // 摊位主/门店:仅查自己关联门店的账单
+            Long storeId = user.getStoreId();
+            if (storeId == null) {
+                return error("未关联门店");
+            }
+            wrapper.eq("md_id", storeId);
+        } else {
+            return error("无权限访问");
+        }
+
+        if (type != null && !type.isEmpty()) {
+            wrapper.eq("type", type);
+        }
+        if (startDate != null && !startDate.isEmpty()) {
+            wrapper.apply("date_format(cretim,'%Y-%m-%d %H:%i:%s') >= date_format('" + startDate + " 00:00:00','%Y-%m-%d %H:%i:%s')");
+        }
+        if (endDate != null && !endDate.isEmpty()) {
+            wrapper.apply("date_format(cretim,'%Y-%m-%d %H:%i:%s') <= date_format('" + endDate + " 23:59:59','%Y-%m-%d %H:%i:%s')");
+        }
+        wrapper.orderByDesc("id");
+
+        Page<UserBilling> page = new Page<>(pageNum, pageSize);
+        IPage<UserBilling> pageResult = userBillingService.page(page, wrapper);
+
+        // 填充门店名称
+        List<UserBilling> records = pageResult.getRecords();
+        fillStoreName(records);
+
+        JSONObject org = new JSONObject();
+        org.put("list", records);
+        org.put("total", pageResult.getTotal());
+        org.put("pageNum", pageResult.getCurrent());
+        org.put("pageSize", pageResult.getSize());
+        return success(MessageUtils.message("no.success"), org);
+    }
+
+    /**
+     * 商家端账单汇总
+     */
+    @Anonymous
+    @Auth
+    @GetMapping("/storeBillingSummary")
+    public AjaxResult storeBillingSummary(@RequestHeader String token,
+                                           @RequestParam(required = false) Long mdId,
+                                           @RequestParam(required = false) String type,
+                                           @RequestParam(required = false) String startDate,
+                                           @RequestParam(required = false) String endDate) {
+        JwtUtil jwtUtil = new JwtUtil();
+        Long userId = Long.valueOf(jwtUtil.getusid(token));
+        InfoUser user = infoUserService.getById(userId);
+        if (user == null) {
+            return error(MessageUtils.message("no.user.not.exist"));
+        }
+
+        QueryWrapper<UserBilling> wrapper = new QueryWrapper<>();
+        String userType = user.getUserType();
+
+        if ("1".equals(userType)) {
+            wrapper.eq("user_id", userId);
+            if (mdId != null) {
+                wrapper.eq("md_id", mdId);
+            }
+        } else if ("3".equals(userType)) {
+            Long storeId = user.getStoreId();
+            if (storeId == null) {
+                return error("未关联门店");
+            }
+            wrapper.eq("md_id", storeId);
+        } else {
+            return error("无权限访问");
+        }
+
+        if (type != null && !type.isEmpty()) {
+            wrapper.eq("type", type);
+        }
+        if (startDate != null && !startDate.isEmpty()) {
+            wrapper.apply("date_format(cretim,'%Y-%m-%d %H:%i:%s') >= date_format('" + startDate + " 00:00:00','%Y-%m-%d %H:%i:%s')");
+        }
+        if (endDate != null && !endDate.isEmpty()) {
+            wrapper.apply("date_format(cretim,'%Y-%m-%d %H:%i:%s') <= date_format('" + endDate + " 23:59:59','%Y-%m-%d %H:%i:%s')");
+        }
+
+        wrapper.select(
+            "IFNULL(SUM(amount),0) as amount",
+            "IFNULL(SUM(divvy),0) as divvy"
+        );
+
+        UserBilling summary = userBillingService.getOne(wrapper);
+        double totalAmount = summary != null && summary.getAmount() != null ? summary.getAmount() : 0;
+        double totalDivvy = summary != null && summary.getDivvy() != null ? summary.getDivvy() : 0;
+        double netIncome = totalAmount - totalDivvy;
+
+        JSONObject org = new JSONObject();
+        org.put("totalAmount", totalAmount);
+        org.put("totalDivvy", totalDivvy);
+        org.put("netIncome", netIncome);
+        return success(MessageUtils.message("no.success"), org);
+    }
+
+    /**
+     * 填充门店名称
+     */
+    private void fillStoreName(List<UserBilling> list) {
+        if (list == null || list.isEmpty()) return;
+        List<Integer> mdIds = list.stream()
+                .map(UserBilling::getMdId)
+                .filter(id -> id != null)
+                .map(Long::intValue)
+                .distinct()
+                .collect(Collectors.toList());
+        if (mdIds.isEmpty()) return;
+        List<PosStore> stores = posStoreService.listByIds(mdIds);
+        list.forEach(billing -> {
+            if (billing.getMdId() != null) {
+                stores.stream()
+                        .filter(s -> Long.valueOf(s.getId()).equals(billing.getMdId()))
+                        .findFirst()
+                        .ifPresent(s -> billing.setMdName(s.getPosName()));
+            }
+        });
+    }
 
     /**
      * 商家日账单数据
@@ -85,7 +239,8 @@ public class UserBillingController extends BaseController {
                                    @RequestParam Long page,
                                    @RequestParam Long size,
                                    @RequestParam String riqi,
-                                   @RequestParam(required = false) Boolean isCancel
+                                   @RequestParam(required = false) Boolean isCancel,
+                                   @RequestParam(required = false) Long mdId
     ) {
         JwtUtil jwtUtil = new JwtUtil();
         Long id = Long.valueOf(jwtUtil.getusid(token));
@@ -94,9 +249,9 @@ public class UserBillingController extends BaseController {
         if (isCancel != null && isCancel) {
             return getDayCancleOrderList(page, size, riqi, user);
         }
-        List<UserBilling> list = userBillingMapper.getdaylist(id, riqi, (page - 1) * size, size);
+        List<UserBilling> list = userBillingMapper.getdaylist(id, riqi, mdId, (page - 1) * size, size);
         setYhInfo(list);
-        BillDTO sum = userBillingMapper.getdaysum(id, riqi);
+        BillDTO sum = userBillingMapper.getdaysum(id, riqi, mdId);
         JSONObject org = new JSONObject();
         org.put("shul", sum.getSul());
         org.put("sum", sum.getShouru());
@@ -113,7 +268,7 @@ public class UserBillingController extends BaseController {
         if ("2".equals(user.getUserType())) {
             setQsList(list, org);
         } else {
-            ShBillingDto shBillingDto = userBillingMapper.getShDaysum(id, riqi);
+            ShBillingDto shBillingDto = userBillingMapper.getShDaysum(id, riqi, mdId);
             org.put("foodAmount", shBillingDto.getFoodAmount());
             org.put("shYh", shBillingDto.getShYh());
             setShList(list, org, user);
@@ -150,7 +305,8 @@ public class UserBillingController extends BaseController {
                                     @RequestParam Long page,
                                     @RequestParam Long size,
                                     @RequestParam String riqi,
-                                    @RequestParam(required = false) Boolean isCancel) {
+                                    @RequestParam(required = false) Boolean isCancel,
+                                    @RequestParam(required = false) Long mdId) {
         JwtUtil jwtUtil = new JwtUtil();
         Long id = Long.valueOf(jwtUtil.getusid(token));
         InfoUser user = infoUserService.getById(id);
@@ -158,9 +314,9 @@ public class UserBillingController extends BaseController {
         if (isCancel != null && isCancel) {
             return getWeekCancleOrderList(page, size, riqi, user);
         }
-        List<UserBilling> list = userBillingMapper.getmeeklist(id, riqi, (page - 1) * size, size);
+        List<UserBilling> list = userBillingMapper.getmeeklist(id, riqi, mdId, (page - 1) * size, size);
         setYhInfo(list);
-        BillDTO sum = userBillingMapper.getmeeksum(id, riqi);
+        BillDTO sum = userBillingMapper.getmeeksum(id, riqi, mdId);
         JSONObject org = new JSONObject();
         org.put("shul", sum.getSul()); //数量
         org.put("sum", sum.getShouru());
@@ -176,7 +332,7 @@ public class UserBillingController extends BaseController {
         if ("2".equals(user.getUserType())) {
             setQsList(list, org);
         } else {
-            ShBillingDto shBillingDto = userBillingMapper.getShMeeksum(id, riqi);
+            ShBillingDto shBillingDto = userBillingMapper.getShMeeksum(id, riqi, mdId);
             org.put("foodAmount", shBillingDto.getFoodAmount());
             org.put("shYh", shBillingDto.getShYh());
             setShList(list, org, user);
@@ -299,16 +455,17 @@ public class UserBillingController extends BaseController {
                                    @RequestParam Long page,
                                    @RequestParam Long size,
                                    @RequestParam String riqi,
-                                   @RequestParam(required = false) Boolean isCancel) {
+                                   @RequestParam(required = false) Boolean isCancel,
+                                   @RequestParam(required = false) Long mdId) {
         JwtUtil jwtUtil = new JwtUtil();
         Long id = Long.valueOf(jwtUtil.getusid(token));
         InfoUser user = infoUserService.getById(id);
         if (isCancel != null && isCancel) {
             return getMonthCancleOrderList(page, size, riqi, user);
         }
-        List<UserBilling> list = userBillingMapper.getmatlist(id, riqi, (page - 1) * size, size);
+        List<UserBilling> list = userBillingMapper.getmatlist(id, riqi, mdId, (page - 1) * size, size);
         setYhInfo(list);
-        BillDTO sum = userBillingMapper.getmatsum(id, riqi);
+        BillDTO sum = userBillingMapper.getmatsum(id, riqi, mdId);
         JSONObject org = new JSONObject();
         org.put("shul", sum.getSul());
         org.put("sum", sum.getShouru());
@@ -324,7 +481,7 @@ public class UserBillingController extends BaseController {
         if ("2".equals(user.getUserType())) {
             setQsList(list, org);
         } else {
-            ShBillingDto shBillingDto = userBillingMapper.getshMonthsum(id, riqi);
+            ShBillingDto shBillingDto = userBillingMapper.getshMonthsum(id, riqi, mdId);
             org.put("foodAmount", shBillingDto.getFoodAmount());
             org.put("shYh", shBillingDto.getShYh());
             setShList(list, org, user);

+ 18 - 18
ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserBillingMapper.java

@@ -49,34 +49,34 @@ public interface UserBillingMapper  extends BaseMapper<UserBilling>
     int getshdtsum(@Param("shid") Long shid);  //反回结果
 
     //商家月账单统计
-    @Select("SELECT IFNULL(COUNT(1),0) AS sul,IFNULL(SUM(amount),0) AS shouru ,IFNULL(SUM(divvy),0) AS commission,IFNULL(SUM(tax),0) AS tax,IFNULL(SUM(behalf_amount),0) AS behalfAmount FROM user_billing WHERE type=0 and user_id=#{shid} and DATE_FORMAT(cretim, '%Y-%m') = #{riqi} and state=0")  //查询语句
-    BillDTO getmatsum(@Param("shid") Long shid, @Param("riqi") String riqi);  //反回结果
+    @Select("SELECT IFNULL(COUNT(1),0) AS sul,IFNULL(SUM(amount),0) AS shouru ,IFNULL(SUM(divvy),0) AS commission,IFNULL(SUM(tax),0) AS tax,IFNULL(SUM(behalf_amount),0) AS behalfAmount FROM user_billing WHERE type=0 and user_id=#{shid} and (#{mdId} IS NULL OR md_id = #{mdId}) and DATE_FORMAT(cretim, '%Y-%m') = #{riqi} and state=0")  //查询语句
+    BillDTO getmatsum(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId);  //反回结果
     //商户查询周月账单商品总金额,商家优惠总金额
-    @Select("SELECT IFNULL(SUM(o.food_amount),0) AS foodAmount,IFNULL(SUM(o.md_discount_amount),0)+IFNULL(SUM(o.md_sales_reduction),0) as shYh  FROM user_billing b left join pos_order o on b.dd_id=o.dd_id WHERE b.type=0 and b.user_id=#{shid} and DATE_FORMAT(b.cretim, '%Y-%m') = #{riqi} and b.state=0")  //查询语句
-    ShBillingDto getshMonthsum(@Param("shid") Long shid, @Param("riqi") String riqi);
+    @Select("SELECT IFNULL(SUM(o.food_amount),0) AS foodAmount,IFNULL(SUM(o.md_discount_amount),0)+IFNULL(SUM(o.md_sales_reduction),0) as shYh  FROM user_billing b left join pos_order o on b.dd_id=o.dd_id WHERE b.type=0 and b.user_id=#{shid} and (#{mdId} IS NULL OR b.md_id = #{mdId}) and DATE_FORMAT(b.cretim, '%Y-%m') = #{riqi} and b.state=0")  //查询语句
+    ShBillingDto getshMonthsum(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId);
     //商家月账单明细
-    @Select("SELECT * FROM user_billing WHERE type=0 and user_id=#{shid} and DATE_FORMAT(cretim, '%Y-%m') = #{riqi}  ORDER BY id desc limit #{page},#{size}")  //查询语句
-    List<UserBilling> getmatlist(@Param("shid") Long shid, @Param("riqi") String riqi,@Param("page") Long page,@Param("size") Long size);  //反回结果
+    @Select("SELECT * FROM user_billing WHERE type=0 and user_id=#{shid} and (#{mdId} IS NULL OR md_id = #{mdId}) and DATE_FORMAT(cretim, '%Y-%m') = #{riqi}  ORDER BY id desc limit #{page},#{size}")  //查询语句
+    List<UserBilling> getmatlist(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId, @Param("page") Long page,@Param("size") Long size);  //反回结果
 
     //商家周账单统计
-    @Select("SELECT IFNULL(COUNT(1),0) AS sul,IFNULL(SUM(amount),0) AS shouru ,IFNULL(SUM(divvy),0) AS commission,IFNULL(SUM(tax),0) AS tax,IFNULL(SUM(behalf_amount),0) AS behalfAmount FROM user_billing WHERE type=0 and user_id=#{shid} and  WEEK(cretim) = WEEK(#{riqi}) and  YEAR(cretim) = YEAR(#{riqi}) and state=0")  //查询语句
-    BillDTO getmeeksum(@Param("shid") Long shid, @Param("riqi") String riqi);  //反回结果
+    @Select("SELECT IFNULL(COUNT(1),0) AS sul,IFNULL(SUM(amount),0) AS shouru ,IFNULL(SUM(divvy),0) AS commission,IFNULL(SUM(tax),0) AS tax,IFNULL(SUM(behalf_amount),0) AS behalfAmount FROM user_billing WHERE type=0 and user_id=#{shid} and (#{mdId} IS NULL OR md_id = #{mdId}) and  WEEK(cretim) = WEEK(#{riqi}) and  YEAR(cretim) = YEAR(#{riqi}) and state=0")  //查询语句
+    BillDTO getmeeksum(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId);  //反回结果
     //商户查询周账单商品总金额,商家优惠总金额
-    @Select("SELECT IFNULL(SUM(o.food_amount),0) AS foodAmount,IFNULL(SUM(o.md_discount_amount),0)+IFNULL(SUM(o.md_sales_reduction),0) as shYh  FROM user_billing b left join pos_order o on b.dd_id=o.dd_id WHERE b.type=0 and b.user_id=#{shid} and  WEEK(b.cretim) = WEEK(#{riqi}) and  YEAR(b.cretim) = YEAR(#{riqi}) and b.state=0")  //查询语句
-    ShBillingDto getShMeeksum(@Param("shid") Long shid, @Param("riqi") String riqi);
+    @Select("SELECT IFNULL(SUM(o.food_amount),0) AS foodAmount,IFNULL(SUM(o.md_discount_amount),0)+IFNULL(SUM(o.md_sales_reduction),0) as shYh  FROM user_billing b left join pos_order o on b.dd_id=o.dd_id WHERE b.type=0 and b.user_id=#{shid} and (#{mdId} IS NULL OR b.md_id = #{mdId}) and  WEEK(b.cretim) = WEEK(#{riqi}) and  YEAR(b.cretim) = YEAR(#{riqi}) and b.state=0")  //查询语句
+    ShBillingDto getShMeeksum(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId);
     //商家周账单明细
-    @Select("SELECT * FROM user_billing WHERE type=0 and user_id=#{shid} and WEEK(cretim) = WEEK(#{riqi}) and  YEAR(cretim) = YEAR(#{riqi}) ORDER BY id desc limit #{page},#{size}")  //查询语句
-    List<UserBilling> getmeeklist(@Param("shid") Long shid, @Param("riqi") String riqi,@Param("page") Long page,@Param("size") Long size);  //反回结果
+    @Select("SELECT * FROM user_billing WHERE type=0 and user_id=#{shid} and (#{mdId} IS NULL OR md_id = #{mdId}) and WEEK(cretim) = WEEK(#{riqi}) and  YEAR(cretim) = YEAR(#{riqi}) ORDER BY id desc limit #{page},#{size}")  //查询语句
+    List<UserBilling> getmeeklist(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId, @Param("page") Long page, @Param("size") Long size);  //反回结果
     //商家日账单统计
-    @Select("SELECT IFNULL(COUNT(1),0) AS sul,IFNULL(SUM(amount),0) AS shouru,IFNULL(SUM(divvy),0) AS commission,IFNULL(SUM(tax),0) AS tax,IFNULL(SUM(behalf_amount),0) AS behalfAmount FROM user_billing WHERE type=0 and user_id=#{shid} and date_format (cretim,'%Y-%m-%d %H:%i:%s') >= date_format (CONCAT(#{riqi}, ' 00:00:00'),'%Y-%m-%d %H:%i:%s') and date_format (cretim,'%Y-%m-%d %H:%i:%s') <= date_format (CONCAT(#{riqi}, ' 23:59:59'),'%Y-%m-%d %H:%i:%s') and state=0")  //查询语句
-    BillDTO getdaysum(@Param("shid") Long shid, @Param("riqi") String riqi);  //反回结果
+    @Select("SELECT IFNULL(COUNT(1),0) AS sul,IFNULL(SUM(amount),0) AS shouru,IFNULL(SUM(divvy),0) AS commission,IFNULL(SUM(tax),0) AS tax,IFNULL(SUM(behalf_amount),0) AS behalfAmount FROM user_billing WHERE type=0 and user_id=#{shid} and (#{mdId} IS NULL OR md_id = #{mdId}) and date_format (cretim,'%Y-%m-%d %H:%i:%s') >= date_format (CONCAT(#{riqi}, ' 00:00:00'),'%Y-%m-%d %H:%i:%s') and date_format (cretim,'%Y-%m-%d %H:%i:%s') <= date_format (CONCAT(#{riqi}, ' 23:59:59'),'%Y-%m-%d %H:%i:%s') and state=0")  //查询语句
+    BillDTO getdaysum(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId);  //反回结果
 
     //商户查询日账单商品总金额,商家优惠总金额
-    @Select("SELECT IFNULL(SUM(o.food_amount),0) AS foodAmount,IFNULL(SUM(o.md_discount_amount),0)+IFNULL(SUM(o.md_sales_reduction),0) as shYh  FROM user_billing b left join pos_order o on b.dd_id=o.dd_id WHERE b.type=0 and b.user_id=#{shid} and date_format (b.cretim,'%Y-%m-%d %H:%i:%s') >= date_format (CONCAT(#{riqi}, ' 00:00:00'),'%Y-%m-%d %H:%i:%s') and date_format (b.cretim,'%Y-%m-%d %H:%i:%s') <= date_format (CONCAT(#{riqi}, ' 23:59:59'),'%Y-%m-%d %H:%i:%s')  ")
-    ShBillingDto getShDaysum(@Param("shid") Long shid, @Param("riqi") String riqi);
+    @Select("SELECT IFNULL(SUM(o.food_amount),0) AS foodAmount,IFNULL(SUM(o.md_discount_amount),0)+IFNULL(SUM(o.md_sales_reduction),0) as shYh  FROM user_billing b left join pos_order o on b.dd_id=o.dd_id WHERE b.type=0 and b.user_id=#{shid} and (#{mdId} IS NULL OR b.md_id = #{mdId}) and date_format (b.cretim,'%Y-%m-%d %H:%i:%s') >= date_format (CONCAT(#{riqi}, ' 00:00:00'),'%Y-%m-%d %H:%i:%s') and date_format (b.cretim,'%Y-%m-%d %H:%i:%s') <= date_format (CONCAT(#{riqi}, ' 23:59:59'),'%Y-%m-%d %H:%i:%s')  ")
+    ShBillingDto getShDaysum(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId);
     //商家日账单明细
-    @Select("SELECT * FROM user_billing WHERE type=0 and user_id=#{shid} and date_format (cretim,'%Y-%m-%d %H:%i:%s') >= date_format (CONCAT(#{riqi}, ' 00:00:00'),'%Y-%m-%d %H:%i:%s') and date_format (cretim,'%Y-%m-%d %H:%i:%s') <= date_format (CONCAT(#{riqi}, ' 23:59:59'),'%Y-%m-%d %H:%i:%s') ORDER BY id desc limit #{page},#{size}")  //查询语句
-    List<UserBilling> getdaylist(@Param("shid") Long shid, @Param("riqi") String riqi,@Param("page") Long page,@Param("size") Long size);  //反回结果
+    @Select("SELECT * FROM user_billing WHERE type=0 and user_id=#{shid} and (#{mdId} IS NULL OR md_id = #{mdId}) and date_format (cretim,'%Y-%m-%d %H:%i:%s') >= date_format (CONCAT(#{riqi}, ' 00:00:00'),'%Y-%m-%d %H:%i:%s') and date_format (cretim,'%Y-%m-%d %H:%i:%s') <= date_format (CONCAT(#{riqi}, ' 23:59:59'),'%Y-%m-%d %H:%i:%s') ORDER BY id desc limit #{page},#{size}")  //查询语句
+    List<UserBilling> getdaylist(@Param("shid") Long shid, @Param("riqi") String riqi, @Param("mdId") Long mdId, @Param("page") Long page, @Param("size") Long size);  //反回结果
     /**
      * 查询Billing
      *

+ 0 - 0
specs/001-food-stall/spec.md


+ 0 - 0
specs/002-table-qrcode/spec.md