|
|
@@ -0,0 +1,187 @@
|
|
|
+package com.usky.vpp.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.usky.vpp.constant.VppDrEventStatus;
|
|
|
+import com.usky.vpp.domain.VppCustomerContact;
|
|
|
+import com.usky.vpp.domain.VppDrEvent;
|
|
|
+import com.usky.vpp.domain.VppDrInvitation;
|
|
|
+import com.usky.vpp.domain.VppSite;
|
|
|
+import com.usky.vpp.mapper.VppCustomerContactMapper;
|
|
|
+import com.usky.vpp.mapper.VppDrInvitationMapper;
|
|
|
+import com.usky.vpp.mapper.VppSiteMapper;
|
|
|
+import com.usky.vpp.service.VppDrUnInvitationIngestService;
|
|
|
+import com.usky.vpp.util.VppAuditHelper;
|
|
|
+import com.usky.vpp.util.VppDrParticipationHelper;
|
|
|
+import com.usky.vpp.util.VppUnEventParser;
|
|
|
+import com.usky.vpp.util.VppUnPayloadHelper;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class VppDrUnInvitationIngestServiceImpl implements VppDrUnInvitationIngestService {
|
|
|
+
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(VppDrUnInvitationIngestServiceImpl.class);
|
|
|
+
|
|
|
+ private static final int REPLY_PENDING = 0;
|
|
|
+ private static final int RESPONSE_PENDING = VppDrEventStatus.PENDING;
|
|
|
+ private static final int SMS_NOT_SENT = 0;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private VppDrInvitationMapper invitationMapper;
|
|
|
+ @Autowired
|
|
|
+ private VppSiteMapper siteMapper;
|
|
|
+ @Autowired
|
|
|
+ private VppCustomerContactMapper contactMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public void syncInvitationsFromUnEvent(VppDrEvent event, Map<String, Object> eventMap) {
|
|
|
+ if (event == null || event.getId() == null || eventMap == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<String> unResourceIds = VppUnEventParser.getTargetResourceIds(eventMap);
|
|
|
+ if (unResourceIds.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> descriptor = VppUnEventParser.getDescriptor(eventMap);
|
|
|
+ LocalDateTime[] period = VppUnEventParser.resolveActivePeriod(eventMap);
|
|
|
+ LocalDate executeStart = resolveExecuteDate(period[0], event.getStartTime());
|
|
|
+ LocalDate executeEnd = resolveExecuteDate(period[1], event.getEndTime());
|
|
|
+ if (executeStart == null) {
|
|
|
+ log.warn("UN 邀约缺少执行开始时间 eventId={}", event.getEventId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (executeEnd == null) {
|
|
|
+ executeEnd = executeStart;
|
|
|
+ }
|
|
|
+ LocalDateTime replyDeadline = VppUnPayloadHelper.getDateTime(descriptor, "deadline");
|
|
|
+ if (replyDeadline == null && event.getStartTime() != null) {
|
|
|
+ replyDeadline = event.getStartTime();
|
|
|
+ }
|
|
|
+ if (replyDeadline == null) {
|
|
|
+ log.warn("UN 邀约缺少回复截止时间 eventId={}", event.getEventId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal demandCapacityKw = resolveUnDemandCapacityKw(event, eventMap);
|
|
|
+ for (String unResourceId : unResourceIds) {
|
|
|
+ syncSingleUnInvitation(event, unResourceId, executeStart, executeEnd, replyDeadline, demandCapacityKw);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void syncSingleUnInvitation(VppDrEvent event,
|
|
|
+ String resourceId,
|
|
|
+ LocalDate executeStart,
|
|
|
+ LocalDate executeEnd,
|
|
|
+ LocalDateTime replyDeadline,
|
|
|
+ BigDecimal demandCapacityKw) {
|
|
|
+ VppSite site = siteMapper.selectOne(new LambdaQueryWrapper<VppSite>()
|
|
|
+ .eq(VppSite::getAccountNo, resourceId.trim())
|
|
|
+ .eq(VppSite::getDeleteFlag, VppAuditHelper.NOT_DELETED)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (site == null) {
|
|
|
+ log.warn("UN resourceID 未匹配站点 unResourceId={} eventId={}", resourceId, event.getEventId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (site.getCustomerId() == null) {
|
|
|
+ log.warn("站点缺少 customerId siteId={} unResourceId={}", site.getId(), resourceId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (findExistingInvitation(event.getId(), site.getId(), site.getCustomerId()) != null) {
|
|
|
+ log.debug("邀约已存在,跳过 eventPk={} siteId={}", event.getId(), site.getId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ VppDrInvitation invitation = new VppDrInvitation();
|
|
|
+ invitation.setInvitationNo(VppAuditHelper.nextInvitationNo());
|
|
|
+ invitation.setDrEventId(event.getId());
|
|
|
+ invitation.setCustomerId(site.getCustomerId());
|
|
|
+ invitation.setSiteId(site.getId());
|
|
|
+ invitation.setExecuteStartDate(executeStart);
|
|
|
+ invitation.setExecuteEndDate(executeEnd);
|
|
|
+ invitation.setReplyDeadline(shiftOneHourEarlier(replyDeadline));
|
|
|
+ invitation.setIssueTime(shiftOneHourEarlier(LocalDateTime.now()));
|
|
|
+ invitation.setTransactionType(event.getEventType());
|
|
|
+ invitation.setResponseType(event.getResponseType());
|
|
|
+ invitation.setDemandCapacityKw(demandCapacityKw);
|
|
|
+ invitation.setDeclaredCapacityKw(BigDecimal.ZERO);
|
|
|
+ invitation.setReplyStatus(REPLY_PENDING);
|
|
|
+ invitation.setResponseStatus(RESPONSE_PENDING);
|
|
|
+ invitation.setSmsNotifyStatus(SMS_NOT_SENT);
|
|
|
+ invitation.setSmsContactId(resolveSmsContactId(site.getCustomerId()));
|
|
|
+ invitation.setEstimatedCompletionRate(VppDrParticipationHelper.calcEstimatedCompletionRate(null, null));
|
|
|
+ invitation.setResponseCompletionRate(VppDrParticipationHelper.calcResponseCompletionRate(null, null));
|
|
|
+ invitation.setRemark("UN邀约 resourceID=" + resourceId);
|
|
|
+ VppAuditHelper.fillCreate(invitation);
|
|
|
+ if (event.getTenantId() != null) {
|
|
|
+ invitation.setTenantId(event.getTenantId());
|
|
|
+ }
|
|
|
+ invitationMapper.insert(invitation);
|
|
|
+ log.info("UN 邀约已入库 eventId={} siteId={} unResourceId={}", event.getEventId(), site.getId(), resourceId);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Long resolveSmsContactId(Long customerId) {
|
|
|
+ if (customerId == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ VppCustomerContact primary = contactMapper.selectOne(new LambdaQueryWrapper<VppCustomerContact>()
|
|
|
+ .eq(VppCustomerContact::getCustomerId, customerId)
|
|
|
+ .eq(VppCustomerContact::getIsPrimary, 1)
|
|
|
+ .eq(VppCustomerContact::getDeleteFlag, VppAuditHelper.NOT_DELETED)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (primary != null) {
|
|
|
+ return primary.getId();
|
|
|
+ }
|
|
|
+ VppCustomerContact any = contactMapper.selectOne(new LambdaQueryWrapper<VppCustomerContact>()
|
|
|
+ .eq(VppCustomerContact::getCustomerId, customerId)
|
|
|
+ .eq(VppCustomerContact::getDeleteFlag, VppAuditHelper.NOT_DELETED)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ return any != null ? any.getId() : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private LocalDate resolveExecuteDate(LocalDateTime fromPeriod, LocalDateTime fromEvent) {
|
|
|
+ if (fromPeriod != null) {
|
|
|
+ return fromPeriod.toLocalDate();
|
|
|
+ }
|
|
|
+ return fromEvent != null ? fromEvent.toLocalDate() : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** UN 报文时间与平台展示/业务规则校正:向前(提前)1 小时。 */
|
|
|
+ private static LocalDateTime shiftOneHourEarlier(LocalDateTime time) {
|
|
|
+ return time != null ? time.minusHours(1) : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private BigDecimal resolveUnDemandCapacityKw(VppDrEvent event, Map<String, Object> eventMap) {
|
|
|
+ BigDecimal demand = VppUnEventParser.extractDemandChargeKw(eventMap);
|
|
|
+ if (demand == null || demand.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ demand = event.getTargetCapacityKw();
|
|
|
+ }
|
|
|
+ if (demand == null || demand.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ demand = BigDecimal.ONE;
|
|
|
+ }
|
|
|
+ return demand;
|
|
|
+ }
|
|
|
+
|
|
|
+ private VppDrInvitation findExistingInvitation(Long drEventId, Long siteId, Long customerId) {
|
|
|
+ LambdaQueryWrapper<VppDrInvitation> wrapper = new LambdaQueryWrapper<VppDrInvitation>()
|
|
|
+ .eq(VppDrInvitation::getDrEventId, drEventId)
|
|
|
+ .eq(VppDrInvitation::getDeleteFlag, VppAuditHelper.NOT_DELETED)
|
|
|
+ .last("LIMIT 1");
|
|
|
+ if (siteId != null) {
|
|
|
+ wrapper.eq(VppDrInvitation::getSiteId, siteId);
|
|
|
+ } else {
|
|
|
+ wrapper.eq(VppDrInvitation::getCustomerId, customerId);
|
|
|
+ }
|
|
|
+ return invitationMapper.selectOne(wrapper);
|
|
|
+ }
|
|
|
+}
|