Browse Source

顧客購入履歴

quyx@nextosd.com 4 months ago
parent
commit
06aee1db3c

+ 3 - 0
yamada-admin/src/main/resources/i18n/messages.properties

@@ -77,6 +77,7 @@ EM014=\u30AA\u30D7\u30B7\u30E7\u30F3\u8A2D\u554F\u6587{0}\u306E\u9078\u629E\u80A
 EM015=\u958B\u59CB\u65E5\u306F\u7D42\u4E86\u65E5\u672A\u6E80\u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093
 EM016=\u8A2D\u554F\u6587{0} \u9078\u629E\u80A2{1}\u306F{2}\u6587\u5B57\u4EE5\u4E0B\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002
 EM017={0}\u3092\u5C11\u306A\u304F\u3068\u30821\u3064\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002
+EM018=[{0}]\u304C\u4E0D\u6B63\u3067\u3059\u3002
 I0003=\u53D6\u8FBC\u306B\u6210\u529F\u3057\u307E\u3057\u305F\u3002
 I0004=\u53D6\u8FBC\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002
 I0008=\u30ED\u30B0\u30A4\u30F3\u3057\u307E\u3057\u305F\u3002
@@ -169,5 +170,7 @@ questionUnit=\u5358\u4F4D
 brandCode=FC
 businessTypeCode=\u696D\u7A2E
 regions=\u30A8\u30EA\u30A2
+customerName=\u9867\u5BA2\u540D
+customerNameKana=\u9867\u5BA2\u540D(\u30AB\u30CA)
 
 

+ 35 - 0
yamada-common/src/main/java/jp/yamada/common/validator/annotation/LmValidBrandCodes.java

@@ -0,0 +1,35 @@
+package jp.yamada.common.validator.annotation;
+
+import jp.yamada.common.validator.constraint.LmValidBrandCodesValidator;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+
+/**
+ * ブランドコード検証注釈
+ * ブランドコードリストの各要素が許容される値であるかどうかを検証するのに使用する
+ *
+ * @author fcbi
+ */
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(validatedBy = LmValidBrandCodesValidator.class)
+public @interface LmValidBrandCodes {
+
+    /**
+     * メッセージ
+     */
+    String message() default "{EM018}";
+
+    /**
+     * グループ
+     */
+    Class<?>[] groups() default {};
+
+    /**
+     * ペイロード
+     */
+    Class<? extends Payload>[] payload() default {};
+}

+ 57 - 0
yamada-common/src/main/java/jp/yamada/common/validator/constraint/LmValidBrandCodesValidator.java

@@ -0,0 +1,57 @@
+package jp.yamada.common.validator.constraint;
+
+import jp.yamada.common.utils.spring.SpringUtils;
+import jp.yamada.common.validator.annotation.LmValidBrandCodes;
+import jp.yamada.common.validator.service.IValidatorService;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * ブランドコード検証ツール
+ * ブランドコードリストの各要素が許容される値であるかどうかを検証する
+ *
+ * @author fcbi
+ */
+public class LmValidBrandCodesValidator implements ConstraintValidator<LmValidBrandCodes, List<String>> {
+
+    private static final Set<String> ALLOWED_BRAND_CODES = Set.of("010", "020", "030");
+    private LmValidBrandCodes validBrandCodes;
+
+    @Override
+    public void initialize(LmValidBrandCodes validBrandCodes) {
+        this.validBrandCodes = validBrandCodes;
+    }
+
+    @Override
+    public boolean isValid(List<String> brandCodes, ConstraintValidatorContext context) {
+        // リストが空の場合、有効とみなす
+        if (brandCodes == null || brandCodes.isEmpty()) {
+            return true;
+        }
+
+        // チェックリストの各要素が許可されたブランドコードの集合に含まれているかどうかを確認する
+        boolean isValid = ALLOWED_BRAND_CODES.containsAll(brandCodes);
+
+        if (!isValid) {
+            // 許可されていないブランドコードの取得
+            List<String> invalidCodes = brandCodes.stream()
+                    .filter(code -> !ALLOWED_BRAND_CODES.contains(code))
+                    .collect(Collectors.toList());
+
+            // エラーメッセージを取得して検証コンテキストに設定する
+            String message = SpringUtils.getBean(IValidatorService.class).getErrorMessage(
+                    validBrandCodes.message(),
+                    String.join(", ", invalidCodes));
+
+            context.disableDefaultConstraintViolation();
+            context.buildConstraintViolationWithTemplate(message)
+                    .addConstraintViolation();
+        }
+
+        return isValid;
+    }
+}

+ 16 - 1
yamada-fcbi/src/main/java/jp/yamada/fcbi/controller/YmdfCustomerController.java

@@ -7,11 +7,14 @@ import jp.yamada.common.core.domain.AjaxResult;
 import jp.yamada.common.core.page.TableDataInfo;
 import jp.yamada.common.enums.BusinessType;
 import jp.yamada.common.utils.poi.ExcelUtil;
+import jp.yamada.common.validator.utils.ValidatorGroup;
+import jp.yamada.fcbi.domain.TBaseOrder;
 import jp.yamada.fcbi.param.*;
 import jp.yamada.fcbi.service.IYmdfCustomerService;
 import jp.yamada.fcbi.service.IYmdfFcMemberService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
@@ -35,7 +38,7 @@ public class YmdfCustomerController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:survey:list')")
     @GetMapping("/customerList")
-    public TableDataInfo customerList(YmdfCustomerParam ymdfCustomerParam)
+    public TableDataInfo customerList(@Validated({ValidatorGroup.AddGroup.class})YmdfCustomerParam ymdfCustomerParam)
     {
         startPage();
         List<YmdfCustomerParam> list = ymdfCustomerService.selectYmdfCustomerList(ymdfCustomerParam);
@@ -43,6 +46,18 @@ public class YmdfCustomerController extends BaseController
     }
 
     /**
+     *   顧客購入履歴の取得
+     */
+    @PreAuthorize("@ss.hasPermi('system:survey:list')")
+    @GetMapping("/customerHistory")
+    public TableDataInfo list(@Validated({ValidatorGroup.AddGroup.class}) YmdfCustomerHistoryParam ymdfCustomerHistoryParam)
+    {
+        startPage();
+        List<YmdfCustomerHistoryParam> list = ymdfCustomerService.selectYmdfCustomerHistoryList(ymdfCustomerHistoryParam);
+        return getDataTable(list);
+    }
+
+    /**
      * 顧客詳細
      */
     @PostMapping("/customerDetail")

+ 25 - 1
yamada-fcbi/src/main/java/jp/yamada/fcbi/domain/YmdfCustomer.java

@@ -3,6 +3,8 @@ package jp.yamada.fcbi.domain;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import jp.yamada.common.annotation.Excel;
 import jp.yamada.common.core.domain.BaseEntity;
+import jp.yamada.common.validator.annotation.LmLength;
+import jp.yamada.common.validator.utils.ValidatorGroup;
 import jp.yamada.fcbi.domain.vo.QuestionInfoVo;
 import jp.yamada.fcbi.domain.vo.RegionInfoVo;
 import lombok.EqualsAndHashCode;
@@ -10,6 +12,7 @@ import lombok.Getter;
 import lombok.Setter;
 
 import java.io.Serial;
+import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
 
@@ -77,7 +80,6 @@ public class YmdfCustomer extends BaseEntity
     /** SMS配信 */
     private Integer smsAllowedFlag;
 
-    private List<String> brandNames ;
 
     /** FCブランド名称 */
     private String fcBrandName;
@@ -86,6 +88,8 @@ public class YmdfCustomer extends BaseEntity
 
     private String fcBrandCode;
 
+    private String brandCode;
+
     private String businessTypeCode;
 
     private String businessTypeName;
@@ -114,4 +118,24 @@ public class YmdfCustomer extends BaseEntity
     private String memberLevelFlagDesc;
     private String dmTargetFlagDesc;
     private String smsAllowedFlagDesc;
+
+    /** 商品名 */
+    private String purchaseProductName;
+
+    /** 購入年月日 */
+    private String purchaseMonth;
+
+    /** 単価 */
+    private BigDecimal purchaseCost;
+
+    /** 数量 */
+    private String purchaseQuantity;
+
+    /** 購入金額 */
+    private BigDecimal purchaseAmount;
+
+    /** 購入状態 */
+    private Integer validPurchaseFlag;
+
+    private String validPurchaseFlagName;
 }

+ 8 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/mapper/YmdfCustomerMapper.java

@@ -24,6 +24,14 @@ public interface YmdfCustomerMapper
     List<YmdfCustomer> selectYmdfCustomerList(YmdfCustomer ymdfCustomer);
 
     /**
+     * 顧客購入履歴の取得
+     *
+     * @param ymdfCustomer 顧客購入履歴の取得
+     * @return 顧客購入履歴の取得
+     */
+    List<YmdfCustomer> selectYmdfCustomerHistoryList(YmdfCustomer ymdfCustomer);
+
+    /**
      * 店舗結果の取得
      *
      * @param ymdfCustomer 店舗結果の取得

+ 56 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/param/YmdfCustomerHistoryParam.java

@@ -0,0 +1,56 @@
+package jp.yamada.fcbi.param;
+
+import jp.yamada.common.validator.annotation.LmLength;
+import jp.yamada.common.validator.utils.ValidatorGroup;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * DM出力対象
+ *
+ * @author fcbi
+ * @date 2025-07-22
+ */
+@Data
+public class YmdfCustomerHistoryParam implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 1L;
+    /** 商品名 */
+    private String purchaseProductName;
+
+    /** 購入年月日 */
+    private String purchaseMonth;
+
+    /** 単価 */
+    private BigDecimal purchaseCost;
+
+    /** 数量 */
+    private String purchaseQuantity;
+
+    /** 購入金額 */
+    private BigDecimal purchaseAmount;
+
+    /** 購入状態 */
+    private Integer validPurchaseFlag;
+
+    /** 顧客名 */
+    @LmLength(min = 1, max = 255, params = {"{customerName}", "255"}, groups = {ValidatorGroup.AddGroup.class})
+    private String customerName;
+    /** 顧客名(カナ) */
+    @LmLength(min = 1, max = 255, params = {"{customerNameKana}", "255"}, groups = {ValidatorGroup.AddGroup.class})
+    private String customerNameKana;
+
+    /** FC */
+    private String brandName;
+
+    /** 店舗名 */
+    private String storeName;
+
+    /** 顧客ID */
+    private String customerId;
+
+    private String validPurchaseFlagName;
+}

+ 8 - 1
yamada-fcbi/src/main/java/jp/yamada/fcbi/param/YmdfCustomerParam.java

@@ -2,6 +2,9 @@ package jp.yamada.fcbi.param;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import jp.yamada.common.annotation.Excel;
+import jp.yamada.common.validator.annotation.LmLength;
+import jp.yamada.common.validator.annotation.LmValidBrandCodes;
+import jp.yamada.common.validator.utils.ValidatorGroup;
 import jp.yamada.fcbi.domain.vo.QuestionInfoVo;
 import jp.yamada.fcbi.domain.vo.RegionInfoVo;
 import lombok.Data;
@@ -24,8 +27,10 @@ public class YmdfCustomerParam implements Serializable {
     /** 顧客ID */
     private String customerId;
     /** 顧客名 */
+    @LmLength(min = 1, max = 255, params = {"{customerName}", "255"}, groups = {ValidatorGroup.AddGroup.class})
     private String customerName;
     /** 顧客名(カナ) */
+    @LmLength(min = 1, max = 255, params = {"{customerNameKana}", "255"}, groups = {ValidatorGroup.AddGroup.class})
     private String customerNameKana;
     /** 店舗名称 */
     private String storeName;
@@ -69,8 +74,10 @@ public class YmdfCustomerParam implements Serializable {
     private Integer emailAllowedFlag;
     /** SMS配信 */
     private Integer smsAllowedFlag;
+    @LmValidBrandCodes(groups = {ValidatorGroup.AddGroup.class})
+    private List<String> brandCodes;
 
-    private List<String> brandNames ;
+    private String brandCode;
 
     private String dmAllowedFlagDesc;
     private String emailAllowedFlagDesc;

+ 8 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/service/IYmdfCustomerService.java

@@ -25,6 +25,14 @@ public interface IYmdfCustomerService
     public List<YmdfCustomerParam> selectYmdfCustomerList(YmdfCustomerParam ymdfCustomerParam);
 
     /**
+     * 顧客購入履歴の取得
+     *
+     * @param ymdfCustomerHistoryParam 顧客購入履歴の取得
+     * @return 顧客購入履歴の取得
+     */
+    public List<YmdfCustomerHistoryParam> selectYmdfCustomerHistoryList(YmdfCustomerHistoryParam ymdfCustomerHistoryParam);
+
+    /**
      * 顧客詳細
      *
      * @param ymdfCustomerParam 顧客詳細

+ 22 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/service/impl/YmdfCustomerServiceImpl.java

@@ -63,6 +63,28 @@ public class YmdfCustomerServiceImpl implements IYmdfCustomerService
     }
 
     /**
+     * 顧客購入履歴の取得
+     *
+     * @param ymdfCustomerHistoryParam 顧客購入履歴の取得
+     * @return 顧客購入履歴の取得
+     */
+    @Override
+    public List<YmdfCustomerHistoryParam> selectYmdfCustomerHistoryList(YmdfCustomerHistoryParam ymdfCustomerHistoryParam) {
+        YmdfCustomer ymdfCustomer = new YmdfCustomer();
+        BeanUtils.copyProperties(ymdfCustomerHistoryParam, ymdfCustomer);
+
+        List<YmdfCustomer> surveyList = ymdfCustomerMapper.selectYmdfCustomerHistoryList(ymdfCustomer);
+
+        return surveyList.stream()
+                .map(survey -> {
+                    YmdfCustomerHistoryParam param = new YmdfCustomerHistoryParam();
+                    BeanUtils.copyProperties(survey, param);
+                    return param;
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
      * 店舗結果の取得
      *
      * @param ymdFcStoreOptionsParam 店舗結果の取得

+ 53 - 4
yamada-fcbi/src/main/resources/mapper/fcbi/YmdfCustomerMapper.xml

@@ -19,6 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="emailAllowedFlag" column="email_allowed_flag"/>
         <result property="lastPurchaseMonth" column="last_purchase_month"/>
         <result property="fcBrandCode" column="fc_brand_code"/>
+        <result property="brandCode" column="brand_code"/>
         <result property="fcBrandName" column="fc_brand_name"/>
         <result property="businessTypeCode" column="business_type_code"/>
         <result property="businessTypeName"    column="business_type_name"    />
@@ -36,6 +37,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="memberLevel" column="member_level"/>
         <result property="email" column="email"/>
         <result property="gender" column="gender"/>
+        <result property="purchaseProductName" column="purchase_product_name"/>
+        <result property="purchaseMonth" column="purchase_month"/>
+        <result property="purchaseCost" column="purchase_cost"/>
+        <result property="purchaseQuantity" column="purchase_quantity"/>
+        <result property="purchaseAmount" column="purchase_amount"/>
+        <result property="validPurchaseFlag" column="valid_purchase_flag"/>
+        <result property="validPurchaseFlagName" column="valid_purchase_flag_name"/>
     </resultMap>
     <sql id="selectYmdfCustomerListVo">
         SELECT
@@ -44,6 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             c.customer_name_kana AS customer_name_kana,
             s.store_name AS store_name,
             s.store_code AS store_code,
+            s.brand_code AS brand_code,
             -- ブランド辞書テーブルを結合してブランド名を取得
             fc_dict.dict_label AS brand_name,
             c.prefecture AS prefecture,
@@ -249,10 +258,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="storeCode != null and storeCode != ''">
                 AND t.store_code = #{storeCode}
             </if>
-            <if test="brandNames != null and  brandNames != ''">
-                AND t.brand_name IN
-                <foreach collection="brandNames" item="brandName" open="(" separator="," close=")">
-                    #{brandName}
+            <if test="brandCodes != null and  brandCodes != ''">
+                AND t.brand_code IN
+                <foreach collection="brandCodes" item="brandCode" open="(" separator="," close=")">
+                    #{brandCode}
                 </foreach>
             </if>
         </where>
@@ -300,4 +309,44 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             c.del_flag = 0
           AND c.customer_id = #{customerId}
     </select>
+
+    <select id="selectYmdfCustomerHistoryList" parameterType="YmdfCustomer" resultMap="YmdfCustomerResult">
+        SELECT
+            cph.purchase_product_name AS purchase_product_name,
+            cph.purchase_month AS purchase_month,
+            cph.purchase_cost AS purchase_cost,
+            s.store_name AS store_name,
+            fc_dict.dict_label AS brand_name,
+            cph.purchase_quantity AS purchase_quantity,
+            cph.purchase_amount AS purchase_amount,
+            cph.valid_purchase_flag AS valid_purchase_flag,
+            flag_dict.dict_label AS valid_purchase_flag_name,
+            c.customer_name AS customer_name,
+            c.customer_name_kana AS customer_name_kana
+        FROM
+            ymdf_customer c
+                INNER JOIN ymdf_customer_purchase_history cph
+                           ON c.customer_id = cph.customer_id
+                               AND cph.del_flag = 0
+                INNER JOIN ymdf_fc_store s
+                           ON cph.fc_store_id = s.fc_store_id
+                               AND s.del_flag = 0
+                LEFT JOIN sys_dict_data fc_dict
+                          ON s.brand_code = fc_dict.dict_value
+                              AND fc_dict.dict_type = 'yamada_fc_brand'
+                LEFT JOIN sys_dict_data flag_dict
+                          ON cph.valid_purchase_flag = flag_dict.dict_value
+                                AND flag_dict.dict_type = 'valid_purchase_flag'
+        WHERE
+            c.del_flag = 0
+          AND cph.customer_id = #{customerId}
+        <if test="customerName != null and customerName != ''">
+            AND c.customer_name LIKE CONCAT('%', #{customerName}, '%')
+        </if>
+        <if test="customerNameKana != null and customerNameKana != ''">
+            AND c.customer_name_kana LIKE CONCAT('%', #{customerNameKana}, '%')
+        </if>
+        ORDER BY
+            cph.purchase_month DESC
+    </select>
 </mapper>