package com.ruixuan.isc.service.impl; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.kuaishou.merchant.open.api.KsMerchantApiException; import com.kuaishou.merchant.open.api.client.AccessTokenKsMerchantClient; import com.kuaishou.merchant.open.api.common.utils.GsonUtils; import com.kuaishou.merchant.open.api.request.distribution.OpenDistributionCpsLeaderOrderCursorListRequest; import com.kuaishou.merchant.open.api.request.distribution.OpenDistributionInvestmentActivityOpenListRequest; import com.kuaishou.merchant.open.api.response.distribution.OpenDistributionCpsLeaderOrderCursorListResponse; import com.kuaishou.merchant.open.api.response.distribution.OpenDistributionInvestmentActivityOpenListResponse; import com.ruixuan.common.utils.Check; import com.ruixuan.common.utils.DateUtils; import com.ruixuan.isc.entity.KuaiShouActivityInfo; import com.ruixuan.isc.entity.KuaishouAccessToken; import com.ruixuan.isc.entity.KuaishouSupplyChain; import com.ruixuan.isc.mapper.KuaishouItemListMapper; import com.ruixuan.isc.mapper.SupplyChainMapper; import com.ruixuan.isc.service.IAccessTokenService; import com.ruixuan.isc.service.ISupplyChainService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j @Service public class SupplyChainServiceImpl implements ISupplyChainService { @Autowired private SupplyChainMapper supplyChainMapper; @Autowired private KuaishouItemListMapper itemListMapper; @Autowired private IAccessTokenService accessTokenService; // 获取订单数据  @Override public List getOrderList(Map requestMap) { List list = supplyChainMapper.getOrderList(requestMap); if (!Check.isNull(list)) { for (int i = 0; i < list.size(); i++) { JSONObject jsonObject = list.get(i); String promoterId = jsonObject.getString("promoterId"); requestMap.put("promoterId", promoterId); List topOrders = supplyChainMapper.getTopOrders(requestMap); jsonObject.put("topOrders", topOrders); } } return list; } //达人带货详情 @Override public List anchorOrderDetail(Map requestMap) { return supplyChainMapper.anchorOrderDetail(requestMap); } //订单统计 @Override public List orderStatistics(Map requestMap) { return supplyChainMapper.orderStatistics(requestMap); } //商品列表 @Override public List itemList(Map requestMap) { List list = supplyChainMapper.itemList(requestMap); return list; } @Override public List itemBindList(Map requestMap) { return supplyChainMapper.itemBindList(requestMap); } @Override public List itemDetail(Map requestMap) { return supplyChainMapper.itemDetail(requestMap); } @Override public List itemServiceCharge(Map requestMap) { return supplyChainMapper.itemServiceCharge(requestMap); } @Override public JSONObject getOrderTotal(Map requestMap) { return supplyChainMapper.getOrderTotal(requestMap); } @Override public Double getOrderTotalRatio(Map ratioMap) { return supplyChainMapper.getOrderTotalRatio(ratioMap); } @Override public JSONObject getAmountTotal(Map requestMap) { return supplyChainMapper.getAmountTotal(requestMap); } @Override public Double getAmountTotalRatio(Map ratioMap) { return supplyChainMapper.getAmountTotalRatio(ratioMap); } @Override public JSONObject getServiceAmountTotal(Map requestMap) { return supplyChainMapper.getServiceAmountTotal(requestMap); } @Override public List getOrderRankRatioList(Map requestMap) { return supplyChainMapper.getOrderRankRatioList(requestMap); } @Override public List getOrderRankList(Map requestMap) { return supplyChainMapper.getOrderRankList(requestMap); } @Override public List getPromoterRankRatioList(Map requestMap) { return supplyChainMapper.getPromoterRankRatioList(requestMap); } @Override public List getPromoterRatioList(Map requestMap) { return supplyChainMapper.getPromoterRatioList(requestMap); } @Override public List exportPromoterTotal(Map requestMap) { return supplyChainMapper.exportPromoterTotal(requestMap); } @Override public List exportPromoter(Map requestMap) { return supplyChainMapper.exportPromoter(requestMap); } @Override public List exportOrder(Map requestMap) { return supplyChainMapper.exportOrder(requestMap); } @Override public List getTopPromoterByItemId(Map requestMap) { return supplyChainMapper.getTopPromoterByItemId(requestMap); } @Override public List bindUserItemList(Map requestMap) { return supplyChainMapper.bindUserItemList(requestMap); } @Override public List getSupplyChainUserList() { return supplyChainMapper.getSupplyChainUserList(); } @Override public boolean unbindUser(Long itemId) { return supplyChainMapper.unbindUser(itemId); } @Override public boolean bindUser(Long itemId, Long userId, String nikeName) { return supplyChainMapper.bindUser(itemId, userId, nikeName); } @Override public List adminReportList(Map requestMap) { return supplyChainMapper.adminReportList(requestMap); } @Override public List userItemDetail(Map requestMap) { return supplyChainMapper.userItemDetail(requestMap); } @Override public JSONObject getTimeIntervalRatio(Map requestMap) { return supplyChainMapper.getTimeIntervalRatio(requestMap); } @Override public List indexStatistics(Map requestMap) { return supplyChainMapper.indexStatistics(requestMap); } @Override public JSONObject itemBindSummary() { return supplyChainMapper.itemBindSummary(); } @Override public JSONObject userItemTotal(Map requestMap) { return supplyChainMapper.userItemTotal(requestMap); } @Override public List exportUserItemDetail(Map requestMap) { return supplyChainMapper.exportUserItemDetail(requestMap); } @Override public JSONObject selectOrderInfo(List promoterIds, String startDate, String endDate) { return supplyChainMapper.selectOrderInfo(promoterIds, startDate, endDate); } @Override public JSONObject selectOrderRate(List promoterIds, List itemIds, Long statDate, Long endDate) { return supplyChainMapper.selectOrderRate(promoterIds, itemIds, statDate, endDate); } @Override public JSONObject selectOrderRateBytedance(List promoterIds, List itemIds, Long statDate, Long endDate) { return supplyChainMapper.selectOrderRateBytedance(promoterIds, itemIds, statDate, endDate); } @Override public List getMonthOrderAmount(Map map) { return supplyChainMapper.getMonthOrderAmount(map); } @Override public List getMonthOrderAmountBytedance(Map map) { return supplyChainMapper.getMonthOrderAmountBytedance(map); } @Override public JSONObject getMonthOrderAmountTotalBytedance(Map map) { return supplyChainMapper.getMonthOrderAmountTotalBytedance(map); } @Override public List getMonthOrderAmountByItemsBytedance(Map map) { return supplyChainMapper.getMonthOrderAmountByItemsBytedance(map); } @Override public JSONObject getMonthOrderAmountTotalByItemsBytedance(Map map) { return supplyChainMapper.getMonthOrderAmountTotalByItemsBytedance(map); } @Override public List getOrderRankRatioListBytedance(Map requestMap) { return supplyChainMapper.getOrderRankRatioListBytedance(requestMap); } @Override public List getOrderRankListBytedance(Map requestMap) { return supplyChainMapper.getOrderRankListBytedance(requestMap); } @Override public List getPromoterRankRatioListBytedance(Map requestMap) { return supplyChainMapper.getPromoterRankRatioListBytedance(requestMap); } @Override public List getPromoterRatioListBytedance(Map requestMap) { return supplyChainMapper.getPromoterRatioListBytedance(requestMap); } @Override public JSONObject selectOrderInfoBytedance(List promoterIds, Long startDate, Long endDate) { return supplyChainMapper.selectOrderInfoBytedance(promoterIds, startDate, endDate); } @Override public List bdReportListV2ByBind(Map requestMap) { return supplyChainMapper.bdReportListV2ByBind(requestMap); } @Override public List exportBindOrder(Map requestMap) { return supplyChainMapper.exportBindOrder(requestMap); } @Override public JSONObject getMonthOrderAmountTotal(Map map) { return supplyChainMapper.getMonthOrderAmountTotal(map); } @Override public JSONObject selectOrderInfoByItemIds(List itemIds, String startDate, String endDate) { return supplyChainMapper.selectOrderInfoByItemIds(itemIds, startDate, endDate); } @Override public List getMonthOrderAmountByItems(Map map) { return supplyChainMapper.getMonthOrderAmountByItems(map); } @Override public JSONObject getMonthOrderAmountTotalByItems(Map map) { return supplyChainMapper.getMonthOrderAmountTotalByItems(map); } @Override public List bdReportList(Map requestMap) { return supplyChainMapper.bdReportList(requestMap); } @Override public List bdDetailList(Map requestMap) { return supplyChainMapper.bdDetailList(requestMap); } @Override public List bdTotal(Map requestMap) { return supplyChainMapper.bdTotal(requestMap); } @Override public List exportBdDetail(Map requestMap) { return supplyChainMapper.exportBdDetail(requestMap); } @Override public String getUserName(Long promoterId) { return supplyChainMapper.getUserName(promoterId); } @Override public List exportBdReportList(Map requestMap) { return supplyChainMapper.exportBdReportList(requestMap); } @Override public List exportAdminReportList(Map requestMap) { return supplyChainMapper.exportAdminReportList(requestMap); } @Override public List getSupplyChainCourtshipUserList() { return supplyChainMapper.getSupplyChainCourtshipUserList(); } @Override public List adminReportListByBind(Map requestMap) { return supplyChainMapper.adminReportListByBind(requestMap); } @Override public List exportAdminReportListByBind(Map requestMap) { return supplyChainMapper.exportAdminReportListByBind(requestMap); } @Override public List bdReportListV2(Map requestMap) { return supplyChainMapper.bdReportListV2(requestMap); } @Override public List bdTotalV2(Map requestMap) { return supplyChainMapper.bdTotalV2(requestMap); } @Override public List bdDetailListV2(Map requestMap) { return supplyChainMapper.bdDetailListV2(requestMap); } @Override public JSONObject selectOrderInfoByItemIdsBytedance(List itemIds, Long startDate, Long endDate) { return supplyChainMapper.selectOrderInfoByItemIdsBytedance(itemIds, startDate, endDate); } @Override public void updateOrder(JSONObject eventJSon) { try { JSONObject info = eventJSon.getJSONObject("info"); if (!Check.isNull(info)) { Long oid = info.getLong("oid"); Integer cpsOrderStatus = info.getInteger("cpsOrderStatus"); if (cpsOrderStatus == 30) { return; } if (cpsOrderStatus == 60) { supplyChainMapper.updateOrderRegimentalSettleAmount(oid, cpsOrderStatus); } else { supplyChainMapper.updateOrder(oid, cpsOrderStatus); } log.info("订单ID:{},状态:{} 修改成功", oid, cpsOrderStatus); } } catch (Exception e) { e.printStackTrace(); } } @Override public void updateItem(JSONObject eventJSon) { try { JSONObject info = eventJSon.getJSONObject("info"); if (!Check.isNull(info)) { Long itemId = info.getLong("itemId"); Integer status = info.getInteger("status"); supplyChainMapper.updateItem(itemId, status); log.info("商品id:{},状态:{} 修改成功", itemId, status); } } catch (Exception e) { e.printStackTrace(); } } @Override public void addList(String beginDate, String endDate, String pcursor) throws InterruptedException { String url = "https://openapi.kwaixiaodian.com"; Long beginTime = DateUtils.getStartLongTime(beginDate); Long endTime = DateUtils.getEndLongTime(endDate); // Map itemMap = getItemMap(); List tokens = accessTokenService.getTokenInfos(); for (KuaishouAccessToken accessToken : tokens) { getInfo(accessToken, beginTime, endTime, url, pcursor, 1); } Thread.sleep(600000); List mgsTokens = accessTokenService.getMgsTokenInfos(); for (KuaishouAccessToken accessToken : mgsTokens) { getMgsInfo(accessToken, beginTime, endTime, url, pcursor, 1); } } private void getInfo(KuaishouAccessToken accessToken, Long beginTime, Long endTime, String url, String pcursor, Integer counts) throws InterruptedException { List list = new ArrayList<>(); String appKey = accessToken.getAppKey(); String signSecret = accessToken.getSignSecret(); if (Check.isNull(signSecret) || Check.isNull(appKey)) { return; } AccessTokenKsMerchantClient client = new AccessTokenKsMerchantClient(url, appKey, signSecret); OpenDistributionCpsLeaderOrderCursorListRequest request = new OpenDistributionCpsLeaderOrderCursorListRequest(); request.setAccessToken(accessToken.getAccessToken()); request.setApiMethodVersion(1L); //排序类型 [1:按指定查询类型降序] [2:按指定查询类型升序] request.setSortType(1); //查询类型 [1:按分销订单创建时间查询] [2:按分销订单更新时间查询][4:按订单实际创建时间查询] request.setQueryType(2); //分销订单状态 [0:全部订单] [30:已付款] [50:已收货] [60:已结算] [80:已失效] request.setCpsOrderStatus(0); request.setDistributorId(0l); request.setBeginTime(beginTime); request.setEndTime(endTime); request.setPcursor(pcursor); request.setPageize(100); request.setFundType(1); OpenDistributionCpsLeaderOrderCursorListResponse response = null; try { response = client.execute(request); } catch (KsMerchantApiException e) { e.printStackTrace(); } JSONObject obj = JSONObject.parseObject(GsonUtils.toJSON(response)); String code = obj.getString("code"); if ("1".equals(code)) { JSONObject data = obj.getJSONObject("data"); pcursor = data.getString("pcursor"); JSONArray orderView = data.getJSONArray("orderView"); for (int i = 0; i < orderView.size(); i++) { JSONObject info = orderView.getJSONObject(i); Integer sendStatus = info.getInteger("sendStatus"); if (Check.isNotNull(sendStatus) && sendStatus == 1) { list.add(info.getLong("oid")); } } } else { log.error("===查询分销团长订单列表(open.distribution.cps.leader.order.cursor.list)失败,信息:{}", obj.getString("msg")); log.error("游标:{},执行次数:{}", pcursor, counts); if (counts <= 3) { getInfo(accessToken, beginTime, endTime, url, pcursor, counts + 1); } } if (Check.isNotNull(list) && list.size() > 0) { supplyChainMapper.updateKuaishouSupplyChain(list); Thread.sleep(200); } if (!"nomore".equals(pcursor)) { getInfo(accessToken, beginTime, endTime, url, pcursor, 1); } } private void getMgsInfo(KuaishouAccessToken accessToken, Long beginTime, Long endTime, String url, String pcursor, Integer counts) throws InterruptedException { List list = new ArrayList<>(); String appKey = accessToken.getAppKey(); String signSecret = accessToken.getSignSecret(); if (Check.isNull(signSecret) || Check.isNull(appKey)) { return; } AccessTokenKsMerchantClient client = new AccessTokenKsMerchantClient(url, appKey, signSecret); OpenDistributionCpsLeaderOrderCursorListRequest request = new OpenDistributionCpsLeaderOrderCursorListRequest(); request.setAccessToken(accessToken.getAccessToken()); request.setApiMethodVersion(1L); //排序类型 [1:按指定查询类型降序] [2:按指定查询类型升序] request.setSortType(1); //查询类型 [1:按分销订单创建时间查询] [2:按分销订单更新时间查询][4:按订单实际创建时间查询] request.setQueryType(2); //分销订单状态 [0:全部订单] [30:已付款] [50:已收货] [60:已结算] [80:已失效] request.setCpsOrderStatus(0); request.setDistributorId(0l); request.setBeginTime(beginTime); request.setEndTime(endTime); request.setPcursor(pcursor); request.setPageize(100); request.setFundType(1); OpenDistributionCpsLeaderOrderCursorListResponse response = null; try { response = client.execute(request); } catch (KsMerchantApiException e) { e.printStackTrace(); } JSONObject obj = JSONObject.parseObject(GsonUtils.toJSON(response)); String code = obj.getString("code"); if ("1".equals(code)) { JSONObject data = obj.getJSONObject("data"); pcursor = data.getString("pcursor"); JSONArray orderView = data.getJSONArray("orderView"); for (int i = 0; i < orderView.size(); i++) { JSONObject info = orderView.getJSONObject(i); Integer sendStatus = info.getInteger("sendStatus"); if (Check.isNotNull(sendStatus) && sendStatus == 1) { list.add(info.getLong("oid")); } } } else { log.error("===查询分销团长订单列表(open.distribution.cps.leader.order.cursor.list)失败,信息:{}", obj.getString("error_msg")); log.error("游标:{},执行次数:{}", pcursor, counts); if (counts <= 3) { getMgsInfo(accessToken, beginTime, endTime, url, pcursor, counts + 1); } } if (Check.isNotNull(list) && list.size() > 0) { supplyChainMapper.updateMgsKuaishouSupplyChain(list); Thread.sleep(200); } if (!"nomore".equals(pcursor)) { getMgsInfo(accessToken, beginTime, endTime, url, pcursor, 1); } } private KuaishouSupplyChain organizeData(JSONObject jsonObject, Map itemMap) { KuaishouSupplyChain supplyChain = new KuaishouSupplyChain(); supplyChain.setOid(jsonObject.getLong("oid")); JSONObject item = jsonObject.getJSONArray("cpsOrderProductView").getJSONObject(0); if (!Check.isNull(item)) { supplyChain.setItemId(item.getLong("itemId")); supplyChain.setItemTitle(item.getString("itemTitle")); supplyChain.setReservePrice(item.getLong("itemPrice")); supplyChain.setImageUrl(itemListMapper.getItemImgUrl(item.getLong("itemId"))); supplyChain.setSellerId(item.getLong("sellerId")); } supplyChain.setOrderStatus(jsonObject.getInteger("cpsOrderStatus")); supplyChain.setOrderCreateTime(jsonObject.getLong("orderCreateTime")); supplyChain.setSendStatus(jsonObject.getInteger("sendStatus")); supplyChain.setSettlementBizType(jsonObject.getInteger("settlementBizType")); supplyChain.setSettlementBizTypeDesc(getSettlementBizTypeDesc(jsonObject.getInteger("settlementBizType"))); supplyChain.setSendTime(jsonObject.getLong("sendTime")); supplyChain.setRecvTime(jsonObject.getLong("recvTime")); supplyChain.setPromoterId(jsonObject.getLong("promotionId")); supplyChain.setPromoterNickName(jsonObject.getString("promotionNickName")); supplyChain.setActivityId(jsonObject.getLong("activityId")); supplyChain.setOrderAmount(jsonObject.getLong("payAmount")); supplyChain.setPayAmount(jsonObject.getLong("payAmount")); supplyChain.setRegimentalPromotionRate(jsonObject.getLong("regimentalPromotionRate")); supplyChain.setShareRate(jsonObject.getLong("shareRateStr")); supplyChain.setBaseAmount(jsonObject.getLong("baseAmount")); supplyChain.setRegimentalPromotionAmount(jsonObject.getLong("regimentalPromotionAmount") / 1000); supplyChain.setTotalRegimentalSettleAmount(jsonObject.getLong("settlementAmount")); supplyChain.setStatDate(DateUtils.tempToDate(jsonObject.getLong("orderCreateTime"))); supplyChain.setItemCommissionRate(itemMap.get(item.getLong("itemId"))); return supplyChain; } private String getSettlementBizTypeDesc(Integer settlementBizType) { return settlementBizType == 1 ? "快分销" : "聚力计划"; } // 获取订单佣金率 public Map getItemMap() { Map returnMap = new HashMap<>(); List list = itemListMapper.itemList(); if (!Check.isNull(list)) { for (int i = 0; i < list.size(); i++) { JSONObject jsonObject = list.get(i); returnMap.put(jsonObject.getLong("itemId"), jsonObject.getLong("itemCommissionRate")); } } return returnMap; } @Override public void addListKuaishouActivityInfo() throws InterruptedException { String url = "https://openapi.kwaixiaodian.com"; List tokens = accessTokenService.getTokenInfos(); for (KuaishouAccessToken accessToken : tokens) { getInfoKuaishouActivityInfo(accessToken, url); } Thread.sleep(600000); List mgsTokens = accessTokenService.getMgsTokenInfos(); for (KuaishouAccessToken mgsToken : mgsTokens) { getMgsInfoKuaishouActivityInfo(mgsToken, url); } } @Override public List getBytedanceOrderHourDataList(Long date) { return supplyChainMapper.getBytedanceOrderHourDataList(date); } @Override public List getKuaishouOrderHourDataList(String date) { return supplyChainMapper.getKuaishouOrderHourDataList(date); } private void getInfoKuaishouActivityInfo(KuaishouAccessToken accessToken, String url) { List list = new ArrayList<>(); String appKey = accessToken.getAppKey(); String signSecret = accessToken.getSignSecret(); if (Check.isNull(signSecret) || Check.isNull(appKey)) { return; } AccessTokenKsMerchantClient client = new AccessTokenKsMerchantClient(url, appKey, signSecret); OpenDistributionInvestmentActivityOpenListRequest request = new OpenDistributionInvestmentActivityOpenListRequest(); request.setAccessToken(accessToken.getAccessToken()); request.setApiMethodVersion(1L); //每页活动数量 request.setLimit(5000); OpenDistributionInvestmentActivityOpenListResponse response = null; try { response = client.execute(request); } catch (KsMerchantApiException e) { e.printStackTrace(); } JSONObject obj = JSONObject.parseObject(GsonUtils.toJSON(response)); String code = obj.getString("code"); if ("1".equals(code)) { JSONObject data = obj.getJSONObject("data"); JSONArray result = data.getJSONArray("result"); for (int i = 0; i < result.size(); i++) { JSONObject info = result.getJSONObject(i); KuaiShouActivityInfo activityInfo = organizeKuaishouActivityInfo(info); list.add(activityInfo); } } else { log.error("===团长查询招商活动列表(open.distribution.investment.activity.open.list)失败,信息:{}" + obj.getString("msg")); return; } if (Check.isNotNull(list) && list.size() > 0) { supplyChainMapper.replaceKuaishouActivityInfo(list); } } private KuaiShouActivityInfo organizeKuaishouActivityInfo(JSONObject jsonObject) { KuaiShouActivityInfo activityInfo = new KuaiShouActivityInfo(); activityInfo.setActivityId(jsonObject.getLong("activityId")); activityInfo.setRegimentalId(jsonObject.getLong("activityUserId")); activityInfo.setActivityTitle(jsonObject.getString("activityTitle")); activityInfo.setActivityType(jsonObject.getInteger("activityType")); activityInfo.setActivityBeginTime(DateUtils.tempToDate(jsonObject.getLong("activityBeginTime"))); activityInfo.setActivityEndTime(DateUtils.tempToDate(jsonObject.getLong("activityEndTime"))); activityInfo.setActivityStatus(jsonObject.getInteger("activityStatus")); JSONObject activityItemDataInfo = jsonObject.getJSONObject("activityItemDataView"); if (!Check.isNull(activityItemDataInfo)) { activityInfo.setApplyItemCount(activityItemDataInfo.getInteger("applyItemCount")); activityInfo.setWaitAuditItemCount(activityItemDataInfo.getInteger("waitAuditItemCount")); activityInfo.setAuditPassItemCount(activityItemDataInfo.getInteger("auditPassItemCount")); } return activityInfo; } private void getMgsInfoKuaishouActivityInfo(KuaishouAccessToken accessToken, String url) { List list = new ArrayList<>(); String appKey = accessToken.getAppKey(); String signSecret = accessToken.getSignSecret(); if (Check.isNull(signSecret) || Check.isNull(appKey)) { return; } AccessTokenKsMerchantClient client = new AccessTokenKsMerchantClient(url, appKey, signSecret); OpenDistributionInvestmentActivityOpenListRequest request = new OpenDistributionInvestmentActivityOpenListRequest(); request.setAccessToken(accessToken.getAccessToken()); request.setApiMethodVersion(1L); //每页活动数量 request.setLimit(5000); OpenDistributionInvestmentActivityOpenListResponse response = null; try { response = client.execute(request); } catch (KsMerchantApiException e) { e.printStackTrace(); } JSONObject obj = JSONObject.parseObject(GsonUtils.toJSON(response)); String code = obj.getString("code"); if ("1".equals(code)) { JSONObject data = obj.getJSONObject("data"); JSONArray result = data.getJSONArray("result"); for (int i = 0; i < result.size(); i++) { JSONObject info = result.getJSONObject(i); KuaiShouActivityInfo activityInfo = organizeKuaishouActivityInfo(info); list.add(activityInfo); } } else { log.error("===团长查询招商活动列表(open.distribution.investment.activity.open.list)失败,信息:{}" + obj.getString("msg")); return; } if (Check.isNotNull(list) && list.size() > 0) { supplyChainMapper.replaceMgsKuaishouActivityInfo(list); } } }