Parcourir la source

feat:加注释

刘云鑫 il y a 4 heures
Parent
commit
a9d7f4e631

+ 5 - 0
alien-store/src/main/java/shop/alien/store/controller/CommonPushTaskController.java

@@ -30,6 +30,11 @@ public class CommonPushTaskController {
 
     private final CommonPushTaskService commonPushTaskService;
 
+    /**
+     * 新增推送任务入口。
+     * <p>调用链:validateTaskForAdd → fillTaskDefaults → auditPushContent → save → savePushReview
+     * →(sendType=1 时)doSendTask → commonPushSendService.send</p>
+     */
     @ApiOperation("新增推送任务")
     @ApiOperationSupport(order = 1)
     @PostMapping("/add")

+ 46 - 2
alien-store/src/main/java/shop/alien/store/service/channel/CommonPushVendorHttpClient.java

@@ -751,6 +751,14 @@ public class CommonPushVendorHttpClient {
         return sendHonorLike(credential, task, Collections.singletonList(deviceId));
     }
 
+    /**
+     * 华为 Push Kit 批量/单条下发:OAuth 换 token → 组装 message body → POST messages:send。
+     * <p>格式转换 credential_json → 请求 URL:</p>
+     * <pre>
+     * 转换前 credential: { "clientId": "115095083", "clientSecret": "..." }
+     * 转换后 URL: https://push-api.cloud.huawei.com/v1/115095083/messages:send
+     * </pre>
+     */
     private CommonPushVendorSendResult sendHuaweiLike(JSONObject credential, CommonPushTask task, List<String> deviceIds) {
         if (deviceIds == null || deviceIds.isEmpty()) {
             return CommonPushVendorSendResult.fail();
@@ -846,6 +854,15 @@ public class CommonPushVendorHttpClient {
         return StringUtils.trimToNull(credential.getString("appSecret"));
     }
 
+    /**
+     * 向华为 OAuth 服务换取 access_token(用于 Authorization: Bearer)。
+     * <p>格式转换 credential → form 参数:</p>
+     * <pre>
+     * 转换前 credential: { "clientId": "115095083", "clientSecret": "xxx" }
+     * 转换后 POST body: grant_type=client_credentials&client_id=115095083&client_secret=xxx
+     * 响应: { "access_token": "AT_xxx", "expires_in": 3600 }
+     * </pre>
+     */
     private String obtainHuaweiAccessToken(JSONObject credential) {
         String clientId = resolveHuaweiOAuthClientId(credential);
         String clientSecret = resolveHuaweiOAuthClientSecret(credential);
@@ -876,6 +893,14 @@ public class CommonPushVendorHttpClient {
         }
     }
 
+    /**
+     * 解析华为 Push API 响应;成功码为 80000000。
+     * <p>格式转换:</p>
+     * <pre>
+     * 转换前 JSON: { "code":"80000000", "requestId":"178169515953238426090801" }
+     * 转换后 CommonPushVendorSendResult: ok, vendorTaskId=requestId
+     * </pre>
+     */
     private CommonPushVendorSendResult parseHuaweiSendResult(String resp, String taskNo, int deviceCount) {
         JSONObject sendJson = JSONObject.parseObject(resp);
         if (sendJson != null && HUAWEI_SUCCESS_CODE.equals(sendJson.getString("code"))) {
@@ -909,6 +934,17 @@ public class CommonPushVendorHttpClient {
 
     /**
      * 华为/荣耀下行消息体:token 必须与 android 同级,放在 message 对象内。
+     * <p>格式转换 pushTokens → 华为 API JSON body:</p>
+     * <pre>
+     * 转换前 List: ["HUAWEI_CN_IQAAAACy1la8..."]
+     * 转换后 body:
+     * {
+     *   "message": {
+     *     "android": { "notification": { "title":"...", "body":"...", "click_action": {"type":3} } },
+     *     "token": ["IQAAAACy1la8..."]
+     *   }
+     * }
+     * </pre>
      *
      * @see <a href="https://developer.huawei.com/consumer/en/doc/HMSCore-References/https-send-api-0000001050986197">Huawei Push send API</a>
      */
@@ -941,7 +977,12 @@ public class CommonPushVendorHttpClient {
     private static final String HUAWEI_PUSH_TOKEN_MARKER = "IQAAA";
 
     /**
-     * HUAWEI_CN_IQAAA... → IQAAA...
+     * 剥离客户端上报的厂商前缀,得到华为 Push Kit 可用 token。
+     * <p>格式转换:</p>
+     * <pre>
+     * 转换前: "HUAWEI_CN_IQAAAACy1la8AAC0PfgZ4PM9..."
+     * 转换后: "IQAAAACy1la8AAC0PfgZ4PM9..."
+     * </pre>
      */
     private String extractHuaweiPushToken(String rawToken) {
         if (StringUtils.isBlank(rawToken)) {
@@ -974,7 +1015,10 @@ public class CommonPushVendorHttpClient {
         return t.substring(0, 8) + "..." + t.substring(t.length() - 4);
     }
 
-    /** 过滤空白、去重后的华为 Push Token,单批 1~1000 个。 */
+    /**
+     * 过滤空白、去重并剥离 HUAWEI_CN_ 前缀,单批最多 1000 个 token。
+     * <p>格式转换 life_user.device_id 列表 → 华为 API token 列表(见 {@link #extractHuaweiPushToken})。</p>
+     */
     private List<String> normalizeHuaweiPushTokens(List<String> deviceIds) {
         if (deviceIds == null || deviceIds.isEmpty()) {
             return Collections.emptyList();

+ 86 - 0
alien-store/src/main/java/shop/alien/store/service/impl/CommonPushSendServiceImpl.java

@@ -48,6 +48,9 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
     private final CommonPushVendorHttpClient commonPushVendorHttpClient;
     private final CommonPushTaskUserService commonPushTaskUserService;
 
+    /**
+     * 查询当前可参与下发的厂商渠道(enable=1、凭证 JSON 合法、未超日配额)。
+     */
     @Override
     public List<CommonPushChannelConfig> listSendableChannels() {
         List<CommonPushChannelConfig> configs = commonPushChannelConfigMapper.selectList(
@@ -78,6 +81,16 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return result;
     }
 
+    /**
+     * 根据任务 targetType / targetConfig 解析推送目标设备列表。
+     * <p>格式转换 targetConfig JSON → 查询条件:</p>
+     * <pre>
+     * targetType=1: 查 life_user 全部 device_id 非空用户
+     * targetConfig={"userIds":[100,101]} → WHERE id IN (100,101) AND device_id 非空
+     * targetConfig={"deviceIds":["tokenA"]} → WHERE device_id IN ('tokenA')
+     * </pre>
+     * <p>输出 {@link CommonPushTargetDto} 列表,见 {@link #toTargetsFromUsers}。</p>
+     */
     @Override
     public List<CommonPushTargetDto> resolveTargets(CommonPushTask task) {
         if (task == null || task.getTargetType() == null) {
@@ -112,12 +125,16 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return Collections.emptyList();
     }
 
+    /** life_user 查询条件:仅包含已上报 device_id(厂商 Push Token)的用户。 */
     private LambdaQueryWrapper<LifeUser> deviceIdNotBlankWrapper() {
         return new LambdaQueryWrapper<LifeUser>()
                 .isNotNull(LifeUser::getDeviceId)
                 .ne(LifeUser::getDeviceId, "");
     }
 
+    /**
+     * 推送任务下发入口:解析目标 → 分组 → 调用各厂商 API。
+     */
     @Override
     public CommonPushSendResultDto send(CommonPushTask task) {
         List<CommonPushTargetDto> targets = resolveTargets(task);
@@ -162,6 +179,14 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return task;
     }
 
+    /**
+     * 向目标设备列表执行多渠道推送(全量广播 + 单推/批量推)。
+     * <p>格式转换 channelMap:</p>
+     * <pre>
+     * 转换前 List&lt;CommonPushChannelConfig&gt;: [{channelCode:"huawei"}, {channelCode:"oppo"}]
+     * 转换后 Map: { "huawei" -> config, "oppo" -> config }
+     * </pre>
+     */
     private CommonPushSendResultDto sendToTargets(CommonPushTask task, List<CommonPushTargetDto> targets) {
         CommonPushSendResultDto result = new CommonPushSendResultDto();
         List<CommonPushChannelConfig> channels = listSendableChannels();
@@ -190,20 +215,28 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         int failedCount = 0;
         Map<String, String> vendorTaskIds = new LinkedHashMap<>();
         Set<String> broadcastHandledChannels = new HashSet<>();
+        // targetType=1 全量:对 apns/huawei/honor/xiaomi/oppo/vivo 依次走厂商广播或批量 API,与后续单推互斥
         if (fullBroadcast) {
             for (String channelCode : FULL_BROADCAST_CHANNELS) {
                 if (!channelMap.containsKey(channelCode)) {
                     continue;
                 }
+                // 标记该渠道已由广播处理,后续 grouped 单推循环会 skip,避免重复下发
                 broadcastHandledChannels.add(channelCode);
                 CommonPushChannelConfig channelConfig = channelMap.get(channelCode);
+                // 本渠道在 groupTargetsByChannel 中分到的设备;无匹配时为空列表(部分厂商仍支持无 token 广播)
                 List<CommonPushTargetDto> channelTargets = grouped.getOrDefault(channelCode, Collections.emptyList());
+                // APNs 需从全量 targets 中筛 iOS deviceToken;其他厂商直接用 channelTargets
                 List<CommonPushTargetDto> broadcastTargets = "apns".equals(channelCode)
                         ? ApnsPushClient.filterApnsTargets(channelTargets, targets)
                         : channelTargets;
+                // 调用对应厂商全量/广播接口(如 OPPO broadcast、华为按 token 批量)
                 CommonPushVendorSendResult sendResult = invokeFullBroadcast(channelCode, channelConfig, task, broadcastTargets);
+                // 成功时写入 vendorTaskIds,格式:huawei_task_id -> requestId
                 CommonPushVendorTaskIdUtil.putTaskId(vendorTaskIds, channelCode, sendResult);
+                // 累加 sentCount、更新 sentTargets,并更新渠道 today_usage
                 sentCount += applyFullBroadcastResult(sendResult.isSuccess(), channelCode, grouped, task, result, channelConfig);
+                // 广播失败时累加 failedCount(无设备时分母按 1 计)
                 failedCount += countFullBroadcastFailure(sendResult.isSuccess(), channelCode, grouped);
             }
         }
@@ -249,10 +282,15 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return result;
     }
 
+    /** estimatedCount 为空或 ≤0 时广播成功计数按 1 计。 */
     private int defaultCount(Integer count) {
         return count == null || count <= 0 ? 1 : count;
     }
 
+    /**
+     * 全量广播渠道推送成功后的计数与结果汇总。
+     * <p>无具体设备时 sentCount 取 task.estimatedCount(默认至少 1)。</p>
+     */
     private int applyFullBroadcastResult(boolean ok, String channelCode,
                                          Map<String, List<CommonPushTargetDto>> grouped,
                                          CommonPushTask task, CommonPushSendResultDto result,
@@ -279,6 +317,7 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return 0;
     }
 
+    /** 按渠道编码调用对应厂商全量/广播推送 API(apns/huawei/honor/xiaomi/oppo/vivo)。 */
     private CommonPushVendorSendResult invokeFullBroadcast(String channelCode, CommonPushChannelConfig config, CommonPushTask task,
                                           List<CommonPushTargetDto> channelTargets) {
         try {
@@ -304,6 +343,7 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         }
     }
 
+    /** 更新渠道 today_usage,失败仅打日志不中断推送。 */
     private void updateChannelUsageSafely(CommonPushChannelConfig config, String channelCode) {
         try {
             updateChannelUsage(config);
@@ -312,6 +352,7 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         }
     }
 
+    /** 全量广播失败时的失败条数(无设备时分母按 1 计)。 */
     private int countFullBroadcastFailure(boolean ok, String channelCode,
                                           Map<String, List<CommonPushTargetDto>> grouped) {
         if (ok) {
@@ -321,6 +362,15 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return channelTargets.isEmpty() ? 1 : channelTargets.size();
     }
 
+    /**
+     * 推送完成后写入 common_push_task_user 发送记录。
+     * <p>格式转换发送状态:</p>
+     * <pre>
+     * 转换前: target 在 sentTargets 中 → status=2(已发送)
+     *         target 仅在 failedTargets 中 → status=0(失败)
+     *         broadcast 占位目标(无 deviceId)→ 单独一条 status=2 记录
+     * </pre>
+     */
     @Override
     public void saveTaskUserRecords(Long pushTaskId, CommonPushSendResultDto sendResult) {
         if (pushTaskId == null || sendResult == null) {
@@ -360,6 +410,15 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         }
     }
 
+    /**
+     * 按 targetConfig.deviceIds 解析目标(去重、trim 后查 life_user)。
+     * <p>格式转换:</p>
+     * <pre>
+     * 转换前 JSONArray: [" HUAWEI_CN_IQAAA... ", "token2"]
+     * 转换后 List&lt;String&gt;: ["HUAWEI_CN_IQAAA...", "token2"]
+     * 再经 toTargetsFromUsers → List&lt;CommonPushTargetDto&gt;
+     * </pre>
+     */
     private List<CommonPushTargetDto> buildTargetsByDeviceIds(JSONArray deviceIds) {
         if (deviceIds == null || deviceIds.isEmpty()) {
             return Collections.emptyList();
@@ -380,6 +439,15 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return toTargetsFromUsers(users);
     }
 
+    /**
+     * 将 life_user 转为推送目标 DTO。
+     * <p>格式转换:</p>
+     * <pre>
+     * 转换前 LifeUser: { id: 100, deviceId: "HUAWEI_CN_IQAAA..." }
+     * 转换后 CommonPushTargetDto: { userId: 100L, deviceId: "HUAWEI_CN_IQAAA...", platform: "android" }
+     * </pre>
+     * <p>华为 token 前缀剥离在 {@link CommonPushVendorHttpClient} 下发时处理。</p>
+     */
     private List<CommonPushTargetDto> toTargetsFromUsers(List<LifeUser> users) {
         if (users == null || users.isEmpty()) {
             return Collections.emptyList();
@@ -392,12 +460,22 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
             CommonPushTargetDto target = new CommonPushTargetDto();
             target.setUserId(user.getId() != null ? user.getId().longValue() : null);
             target.setDeviceId(user.getDeviceId());
+            // TODO 这个 platform 是根据 deviceId 自动判断的,这里先默认 android 了?怎么判断是 android 还是 ios?
             target.setPlatform("android");
             targets.add(target);
         }
         return targets;
     }
 
+    /**
+     * 按厂商渠道对推送目标分组,供后续逐渠道调用 API。
+     * <p>格式转换 targetConfig → preferredChannel:</p>
+     * <pre>
+     * 转换前 String: "{\"vendorChannel\":\"huawei\"}"
+     * 转换后 String: "huawei"(小写;未配置则为 null,走 platform 自动选择)
+     * </pre>
+     * <p>输出示例:{ "huawei" -> [target1, target2], "apns" -> [target3] }</p>
+     */
     private Map<String, List<CommonPushTargetDto>> groupTargetsByChannel(List<CommonPushTargetDto> targets,
                                                                          Map<String, CommonPushChannelConfig> channelMap,
                                                                          String targetConfigJson) {
@@ -419,6 +497,11 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return grouped;
     }
 
+    /**
+     * 为单个目标解析厂商渠道编码。
+     * <p>优先级:targetConfig.vendorChannel → iOS 用 apns → Android 用 channelMap 中优先级最高渠道。</p>
+     * <p>Android 优先级:huawei(1) &gt; honor(2) &gt; xiaomi(3) &gt; oppo(4) &gt; vivo(5) &gt; samsung(6)</p>
+     */
     private String resolveChannelCode(CommonPushTargetDto target,
                                       Map<String, CommonPushChannelConfig> channelMap,
                                       String preferredChannel) {
@@ -436,6 +519,7 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return androidChannels.isEmpty() ? null : androidChannels.get(0);
     }
 
+    /** Android 厂商渠道自动选择时的排序权重(越小越优先)。 */
     private int channelPriority(String channelCode) {
         switch (channelCode) {
             case "huawei":
@@ -462,6 +546,7 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return StringUtils.lowerCase(platform.trim());
     }
 
+    /** 判断渠道是否已达 daily_quota 上限(0 表示不限)。 */
     private boolean isQuotaExceeded(CommonPushChannelConfig config) {
         if (config.getDailyQuota() == null || config.getDailyQuota() <= 0) {
             return false;
@@ -470,6 +555,7 @@ public class CommonPushSendServiceImpl implements CommonPushSendService {
         return usage >= config.getDailyQuota();
     }
 
+    /** 单推成功后 today_usage +1 并写回 common_push_channel_config。 */
     private void updateChannelUsage(CommonPushChannelConfig config) {
         int usage = config.getTodayUsage() == null ? 0 : config.getTodayUsage();
         config.setTodayUsage(usage + 1);

+ 31 - 1
alien-store/src/main/java/shop/alien/store/service/impl/CommonPushTaskServiceImpl.java

@@ -50,6 +50,10 @@ public class CommonPushTaskServiceImpl extends ServiceImpl<CommonPushTaskMapper,
     private final AiContentModerationUtil aiContentModerationUtil;
     private final CommonPushTaskStatsService commonPushTaskStatsService;
 
+    /**
+     * 新增推送任务:校验 → 填默认值 → AI 审核 → 入库 → 按 sendType 决定是否立即下发。
+     * <p>sendType=1 立即发送时调用 {@link #doSendTask};sendType=2 仅入库等待定时任务。</p>
+     */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public R<String> add(CommonPushTask task) {
@@ -171,6 +175,15 @@ public class CommonPushTaskServiceImpl extends ServiceImpl<CommonPushTaskMapper,
         }
     }
 
+    /**
+     * 执行推送并回写任务状态。
+     * <p>成功:status=2(已发送),回填 actualCount、vendorTaskIds;失败:status=4。</p>
+     * <p>格式转换:vendorTaskIds Map → 字符串存入 common_push_task.vendor_task_ids</p>
+     * <pre>
+     * 转换前 Map: { "huawei_task_id": "178169515953238426090801" }
+     * 转换后 String: "huawei_task_id: 178169515953238426090801"
+     * </pre>
+     */
     private R<String> doSendTask(CommonPushTask task) {
         CommonPushSendResultDto sendResult;
         try {
@@ -195,6 +208,7 @@ public class CommonPushTaskServiceImpl extends ServiceImpl<CommonPushTaskMapper,
         return R.success(sendResult.getMessage());
     }
 
+    /** 将 Date 格式化为界面展示用字符串 yyyy-MM-dd HH:mm:ss(定时任务提示文案)。 */
     private String formatDateTime(Date date) {
         if (date == null) {
             return "";
@@ -218,6 +232,11 @@ public class CommonPushTaskServiceImpl extends ServiceImpl<CommonPushTaskMapper,
         return result.isSuccess() ? R.data(result, result.getMessage()) : R.fail(result.getMessage());
     }
 
+    /**
+     * 新增任务参数校验。
+     *
+     * @return null 表示通过;非 null 为 R.fail 可直接返回
+     */
     private R<String> validateTaskForAdd(CommonPushTask task) {
         if (task == null) {
             return R.fail("任务不能为空");
@@ -252,7 +271,9 @@ public class CommonPushTaskServiceImpl extends ServiceImpl<CommonPushTaskMapper,
     }
 
     /**
-     * @return 审核驳回原因,通过时返回 null
+     * AI 审核推送标题与正文(敏感词/违规内容)。
+     *
+     * @return 驳回原因;通过时返回 null
      */
     private String auditPushContent(CommonPushTask task) {
         AiContentModerationUtil.AuditResult titleAudit =
@@ -270,6 +291,7 @@ public class CommonPushTaskServiceImpl extends ServiceImpl<CommonPushTaskMapper,
         return null;
     }
 
+    /** 写入 common_push_review 审核记录(通过/驳回及原因)。 */
     private void savePushReview(Long pushTaskId, boolean auditPassed, String rejectReason) {
         CommonPushReview review = new CommonPushReview();
         review.setPushTaskId(pushTaskId);
@@ -285,6 +307,14 @@ public class CommonPushTaskServiceImpl extends ServiceImpl<CommonPushTaskMapper,
         commonPushReviewService.save(review);
     }
 
+    /**
+     * 填充任务默认值(未传字段时)。
+     * <p>格式转换 taskNo:</p>
+     * <pre>
+     * 转换前: taskNo = null
+     * 转换后: taskNo = "TS202606171916012942"  (TS + yyyyMMddHHmmss + 4位随机数)
+     * </pre>
+     */
     private void fillTaskDefaults(CommonPushTask task) {
         if (StringUtils.isBlank(task.getTaskNo())) {
             task.setTaskNo("TS" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())

+ 9 - 0
alien-store/src/main/java/shop/alien/store/service/impl/CommonPushTaskStatsServiceImpl.java

@@ -141,6 +141,15 @@ public class CommonPushTaskStatsServiceImpl implements CommonPushTaskStatsServic
         taskNum.setShowSum(stats.getShowSum());
     }
 
+    /**
+     * 推送成功后按厂商初始化 common_push_task_num 统计行。
+     * <p>格式转换 vendorTaskIds key → phoneType:</p>
+     * <pre>
+     * 转换前 Map key: "huawei_task_id"
+     * 转换后 phoneType: "3"(见 CommonPushPhoneType.HUAWEI)
+     * expectedSend: task.estimatedCount 转字符串,如 "1000"
+     * </pre>
+     */
     @Override
     public void initTaskNumRecords(Long pushTaskId, Map<String, String> vendorTaskIds, Integer estimatedCount) {
         if (pushTaskId == null || vendorTaskIds == null || vendorTaskIds.isEmpty()) {

+ 17 - 0
alien-store/src/main/java/shop/alien/store/util/CommonPushVendorTaskIdUtil.java

@@ -14,6 +14,14 @@ public final class CommonPushVendorTaskIdUtil {
     private CommonPushVendorTaskIdUtil() {
     }
 
+    /**
+     * 将各厂商 task_id Map 格式化为入库字符串(common_push_task.vendor_task_ids)。
+     * <p>格式转换:</p>
+     * <pre>
+     * 转换前 Map: { "huawei_task_id": "178169515953238426090801", "oppo_message_id": "msg123" }
+     * 转换后 String: "huawei_task_id: 178169515953238426090801, oppo_message_id: msg123"
+     * </pre>
+     */
     public static String format(Map<String, String> vendorTaskIds) {
         if (vendorTaskIds == null || vendorTaskIds.isEmpty()) {
             return null;
@@ -54,6 +62,14 @@ public final class CommonPushVendorTaskIdUtil {
         return result;
     }
 
+    /**
+     * 广播/批量推送成功后写入厂商 task_id(key 规则:{channelCode}_task_id)。
+     * <p>格式转换:</p>
+     * <pre>
+     * 转换前: channelCode="huawei", sendResult.vendorTaskId="178169515953238426090801"
+     * 转换后 Map 条目: huawei_task_id -> 178169515953238426090801
+     * </pre>
+     */
     public static void putTaskId(Map<String, String> vendorTaskIds, String channelCode,
                                  CommonPushVendorSendResult sendResult) {
         if (vendorTaskIds == null || sendResult == null || !sendResult.isSuccess()) {
@@ -68,6 +84,7 @@ public final class CommonPushVendorTaskIdUtil {
         }
     }
 
+    /** 单推成功时合并厂商 task_id(同渠道多次推送用逗号拼接)。 */
     public static void mergeTaskId(Map<String, String> vendorTaskIds, String channelCode,
                                    CommonPushVendorSendResult sendResult) {
         if (vendorTaskIds == null || sendResult == null || !sendResult.isSuccess()) {