From 3ef8fc4799d36e200f3601736c3c273803fb2278 Mon Sep 17 00:00:00 2001 From: Donghuang Date: Sun, 12 Sep 2021 21:17:45 +0800 Subject: [PATCH] post cdr --- .../CallDetailRecordController.java | 3 +- .../cms/service/CallDetailRecordService.java | 4 +- .../impl/CallDetailRecordServiceImpl.java | 8 +- .../yo/mapper/CallDetailRecordAllMapper.java | 33 +++++ .../yo/mapper/CallDetailRecordAllMapper.xml | 32 +++++ .../yo/mapper/CallDetailRecordMapper.java | 24 ++-- .../yo/mapper/CallDetailRecordMapper.xml | 20 --- .../yo/mapper/CallDetailRecordMapperTest.java | 4 +- .../com/pudonghot/yo/model/domain/Agent.java | 1 + .../yo/model/domain/CallDetailRecord.java | 90 +------------ .../yo/model/domain/CallDetailRecordAll.java | 16 +++ .../yo/model/domain/CallDetailRecordBase.java | 120 ++++++++++++++++++ .../fsagent/controller/PostCdrController.java | 43 ++++++- .../controller/request/CdrCtrlrReqDTO.java | 79 ++++++++++++ .../yo/fsagent/listener/ChannelDestroy.java | 2 +- .../service/CallDetailRecordService.java | 17 +++ .../dubbo/impl/CampaignDialServiceImpl.java | 3 +- .../impl/CallDetailRecordServiceImpl.java | 34 +++++ .../CallDetailtRecordCreateServReq.java | 46 +++++++ .../templates/config/format_cdr.conf.xml | 10 +- .../com/pudonghot/yo/fsagent/TestDriver.java | 19 ++- start.sh | 2 +- 22 files changed, 466 insertions(+), 144 deletions(-) create mode 100644 lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordAllMapper.java create mode 100644 lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordAllMapper.xml create mode 100644 lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecordAll.java create mode 100644 lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecordBase.java create mode 100644 server/src/main/java/com/pudonghot/yo/fsagent/controller/request/CdrCtrlrReqDTO.java create mode 100644 server/src/main/java/com/pudonghot/yo/fsagent/service/CallDetailRecordService.java create mode 100644 server/src/main/java/com/pudonghot/yo/fsagent/service/impl/CallDetailRecordServiceImpl.java create mode 100644 server/src/main/java/com/pudonghot/yo/fsagent/service/request/CallDetailtRecordCreateServReq.java diff --git a/cms/src/main/java/com/pudonghot/yo/cms/controller/CallDetailRecordController.java b/cms/src/main/java/com/pudonghot/yo/cms/controller/CallDetailRecordController.java index 20f36d83..b70644a4 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/controller/CallDetailRecordController.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/controller/CallDetailRecordController.java @@ -21,6 +21,7 @@ import com.pudonghot.yo.mapper.CallRecordingMapper; import com.pudonghot.yo.cms.model.HangupCauseMapping; import com.pudonghot.yo.model.domain.CallDetailRecord; import com.pudonghot.yo.model.dbobject.CallDetailReport; +import com.pudonghot.yo.model.domain.CallDetailRecordAll; import org.springframework.beans.factory.annotation.Value; import com.pudonghot.yo.cms.form.FormListCallDetailRecord; import com.wacai.tigon.web.controller.BaseQueryController; @@ -51,7 +52,7 @@ filterCols = { @Slf4j @RequestMapping("/cms/api/call-detail-record") public class CallDetailRecordController - extends BaseQueryController + extends BaseQueryController implements SessionAbility { @Autowired diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/CallDetailRecordService.java b/cms/src/main/java/com/pudonghot/yo/cms/service/CallDetailRecordService.java index 0c00f68a..67821963 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/service/CallDetailRecordService.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/CallDetailRecordService.java @@ -2,8 +2,8 @@ package com.pudonghot.yo.cms.service; import java.util.List; import com.wacai.tigon.service.BaseQueryService; -import com.pudonghot.yo.model.domain.CallDetailRecord; import com.pudonghot.yo.model.dbobject.CallDetailReport; +import com.pudonghot.yo.model.domain.CallDetailRecordAll; import com.pudonghot.yo.model.request.ReqCallDetailRecordAccountReport; import com.pudonghot.yo.cms.service.request.CallDetailRecordDeleteServReq; @@ -11,7 +11,7 @@ import com.pudonghot.yo.cms.service.request.CallDetailRecordDeleteServReq; * @author Donghuang * @date Oct 21, 2020 21:10:19 */ -public interface CallDetailRecordService extends BaseQueryService { +public interface CallDetailRecordService extends BaseQueryService { /** * account report diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/CallDetailRecordServiceImpl.java b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/CallDetailRecordServiceImpl.java index c5c9c518..3d7570fb 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/CallDetailRecordServiceImpl.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/CallDetailRecordServiceImpl.java @@ -13,9 +13,9 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import com.pudonghot.yo.mapper.CallRecordingMapper; import com.pudonghot.yo.model.domain.CallRecording; -import com.pudonghot.yo.model.domain.CallDetailRecord; -import com.pudonghot.yo.mapper.CallDetailRecordMapper; import com.pudonghot.yo.model.dbobject.CallDetailReport; +import com.pudonghot.yo.mapper.CallDetailRecordAllMapper; +import com.pudonghot.yo.model.domain.CallDetailRecordAll; import com.pudonghot.yo.cms.service.CallDetailRecordService; import org.springframework.beans.factory.annotation.Autowired; import com.wacai.tigon.service.support.BaseQueryServiceSupport; @@ -29,8 +29,8 @@ import com.pudonghot.yo.cms.service.request.CallDetailRecordDeleteServReq; @Slf4j @Service public class CallDetailRecordServiceImpl - extends BaseQueryServiceSupport - implements CallDetailRecordService{ + extends BaseQueryServiceSupport + implements CallDetailRecordService { @Autowired private CallRecordingMapper recordingMapper; diff --git a/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordAllMapper.java b/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordAllMapper.java new file mode 100644 index 00000000..7bedaa44 --- /dev/null +++ b/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordAllMapper.java @@ -0,0 +1,33 @@ +package com.pudonghot.yo.mapper; + +import java.util.List; +import me.chyxion.tigon.mybatis.BaseMapper; +import org.apache.ibatis.annotations.Param; +import com.pudonghot.yo.model.dbobject.CallDetailReport; +import com.pudonghot.yo.model.domain.CallDetailRecordAll; +import com.pudonghot.yo.model.domain.CallDetailRecordBase; +import com.pudonghot.yo.model.request.ReqCallDetailRecordAccountReport; + +/** + * @author Donghuang + * @date Sep 09, 2021 01:06:07 + */ +public interface CallDetailRecordAllMapper extends BaseMapper { + + /** + * insert base model + * + * @param model model + * @return insert row + */ + int insert(@Param(PARAM_MODEL_KEY) CallDetailRecordBase model); + + /** + * account report + * + * @param arg arg + * @return account report + */ + List accountReport( + @Param("arg") ReqCallDetailRecordAccountReport arg); +} diff --git a/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordAllMapper.xml b/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordAllMapper.xml new file mode 100644 index 00000000..f5d3e4b3 --- /dev/null +++ b/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordAllMapper.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordMapper.java b/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordMapper.java index ff354af3..c3799a45 100644 --- a/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordMapper.java +++ b/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordMapper.java @@ -1,14 +1,10 @@ package com.pudonghot.yo.mapper; -import java.util.List; - -import lombok.val; -import me.chyxion.tigon.mybatis.BaseMapper; import me.chyxion.tigon.mybatis.Search; import org.apache.ibatis.annotations.Param; +import me.chyxion.tigon.mybatis.BaseMapper; import com.pudonghot.yo.model.domain.CallDetailRecord; -import com.pudonghot.yo.model.dbobject.CallDetailReport; -import com.pudonghot.yo.model.request.ReqCallDetailRecordAccountReport; +import com.pudonghot.yo.model.domain.CallDetailRecordBase; /** * @author Donghuang
@@ -16,6 +12,14 @@ import com.pudonghot.yo.model.request.ReqCallDetailRecordAccountReport; */ public interface CallDetailRecordMapper extends BaseMapper { + /** + * insert base model + * + * @param model model + * @return insert row + */ + int insert(@Param(PARAM_MODEL_KEY) CallDetailRecordBase model); + /** * 呼叫在灰名单中,有效 * @@ -27,14 +31,6 @@ public interface CallDetailRecordMapper extends BaseMapper accountReport( - @Param("arg") ReqCallDetailRecordAccountReport arg); - /** * find by conn id * diff --git a/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordMapper.xml b/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordMapper.xml index b084e898..d9b7ad18 100644 --- a/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordMapper.xml +++ b/lib/mapper/src/main/java/com/pudonghot/yo/mapper/CallDetailRecordMapper.xml @@ -34,24 +34,4 @@ ) t - - diff --git a/lib/mapper/src/test/java/com/pudonghot/yo/mapper/CallDetailRecordMapperTest.java b/lib/mapper/src/test/java/com/pudonghot/yo/mapper/CallDetailRecordMapperTest.java index 12588e56..8445aa66 100644 --- a/lib/mapper/src/test/java/com/pudonghot/yo/mapper/CallDetailRecordMapperTest.java +++ b/lib/mapper/src/test/java/com/pudonghot/yo/mapper/CallDetailRecordMapperTest.java @@ -30,6 +30,8 @@ import java.util.Scanner; public class CallDetailRecordMapperTest { @Autowired private CallDetailRecordMapper mapper; + @Autowired + private CallDetailRecordAllMapper allMapper; @Test public void testList() { @@ -48,7 +50,7 @@ public class CallDetailRecordMapperTest { arg.setTenantId(1); arg.setDateFrom(DateUtils.parseDate("2020-10-10", "yyyy-MM-dd")); arg.setDateTo(DateUtils.parseDate("2020-10-11", "yyyy-MM-dd")); - val result = mapper.accountReport(arg); + val result = allMapper.accountReport(arg); log.info("List [{}].", result); } diff --git a/lib/model/src/main/java/com/pudonghot/yo/model/domain/Agent.java b/lib/model/src/main/java/com/pudonghot/yo/model/domain/Agent.java index 1a3c24a5..889793a6 100644 --- a/lib/model/src/main/java/com/pudonghot/yo/model/domain/Agent.java +++ b/lib/model/src/main/java/com/pudonghot/yo/model/domain/Agent.java @@ -38,6 +38,7 @@ public class Agent extends TaggableDomain { private String queues; public enum Type { + SYSTEM, PERSON, ROBOT, IVR diff --git a/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecord.java b/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecord.java index bc86aa30..7723fa51 100644 --- a/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecord.java +++ b/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecord.java @@ -2,12 +2,7 @@ package com.pudonghot.yo.model.domain; import lombok.Getter; import lombok.Setter; -import java.util.Date; -import com.wacai.tigon.model.M0; import me.chyxion.tigon.mybatis.Table; -import lombok.RequiredArgsConstructor; -import me.chyxion.tigon.mybatis.NotUpdate; -import lombok.experimental.FieldNameConstants; /** * @author Donghuang
@@ -16,88 +11,7 @@ import lombok.experimental.FieldNameConstants; @Getter @Setter @Table("br_call_detail_record") -@FieldNameConstants(prefix = "") -public class CallDetailRecord extends M0 { - @NotUpdate - private Integer tenantId; - @NotUpdate - private String tenantCode; - @NotUpdate - private String account; - @NotUpdate - private String connId; +public class CallDetailRecord extends CallDetailRecordBase { + private static final long serialVersionUID = 1L; - @NotUpdate - private DialType dialType; - @NotUpdate - private CallType callType; - @NotUpdate - private Agent.Type agentType; - @NotUpdate - private Integer campaignId; - @NotUpdate - private String caseKey; - - @NotUpdate - private String uuid; - @NotUpdate - private String callUuid; - @NotUpdate - private String callerNumber; - @NotUpdate - private String calledNumber; - @NotUpdate - private Integer trunkId; - @NotUpdate - private String callingPartyNumber; - @NotUpdate - private Date startStamp; - @NotUpdate - private Date answerStamp; - @NotUpdate - private Date endStamp; - @NotUpdate - private Long duration; - @NotUpdate - private Long mduration; - @NotUpdate - private Long billsec; - @NotUpdate - private Long billmsec; - @NotUpdate - private String endpointDisposition; - @NotUpdate - private String hangupCause; - @NotUpdate - private String hangupDisposition; - private Boolean deleted; - - @RequiredArgsConstructor - public enum DialType { - MANUAL("手"), - INBOUND("进"), - CAMPAIGN("预"); - - @Getter - private final String text; - } - - @RequiredArgsConstructor - public enum CallDirection { - INCOMING("来电"), - OUTGOING("去电"); - - @Getter - private final String text; - } - - @RequiredArgsConstructor - public enum CallType { - INTERNAL("内线"), - INBOUND("进线"), - OUTBOUND("外呼"); - - @Getter - private final String text; - } } diff --git a/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecordAll.java b/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecordAll.java new file mode 100644 index 00000000..d5fefb55 --- /dev/null +++ b/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecordAll.java @@ -0,0 +1,16 @@ +package com.pudonghot.yo.model.domain; + +import lombok.Getter; +import lombok.Setter; +import me.chyxion.tigon.mybatis.Table; + +/** + * @author Donghuang
+ * Nov 14, 2019 11:32:42 + */ +@Getter +@Setter +@Table("br_call_detail_record_all") +public class CallDetailRecordAll extends CallDetailRecordBase { + private static final long serialVersionUID = 1L; +} diff --git a/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecordBase.java b/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecordBase.java new file mode 100644 index 00000000..ab3e1983 --- /dev/null +++ b/lib/model/src/main/java/com/pudonghot/yo/model/domain/CallDetailRecordBase.java @@ -0,0 +1,120 @@ +package com.pudonghot.yo.model.domain; + +import lombok.Getter; +import lombok.Setter; +import java.util.Date; +import com.wacai.tigon.model.M0; +import lombok.RequiredArgsConstructor; +import me.chyxion.tigon.mybatis.NotUpdate; +import lombok.experimental.FieldNameConstants; + +/** + * @author Donghuang + * @date Sep 09, 2021 22:47:13 + */ +@Getter +@Setter +@FieldNameConstants(prefix = "") +public class CallDetailRecordBase extends M0 { + @NotUpdate + private Integer tenantId; + @NotUpdate + private String tenantCode; + @NotUpdate + private String account; + @NotUpdate + private String connId; + + @NotUpdate + private DialType dialType; + @NotUpdate + private CallType callType; + @NotUpdate + private Agent.Type agentType; + @NotUpdate + private Integer campaignId; + @NotUpdate + private String caseKey; + + @NotUpdate + private String uuid; + @NotUpdate + private String callUuid; + @NotUpdate + private String callerNumber; + @NotUpdate + private String calledNumber; + @NotUpdate + private Integer trunkId; + @NotUpdate + private String callingPartyNumber; + @NotUpdate + private Date startStamp; + @NotUpdate + private Date answerStamp; + @NotUpdate + private Date endStamp; + @NotUpdate + private Long duration; + @NotUpdate + private Long mduration; + @NotUpdate + private Long billsec; + @NotUpdate + private Long billmsec; + @NotUpdate + private String endpointDisposition; + @NotUpdate + private String hangupCause; + @NotUpdate + private String hangupDisposition; + private Boolean deleted; + + /** + * {@inheritDoc} + */ + @Override + public void beforeInsert() { + if (agentType == null) { + if ("SYSTEM".equals(account)) { + agentType = Agent.Type.SYSTEM; + } + else { + agentType = Agent.Type.PERSON; + } + } + + if (deleted == null) { + deleted = Boolean.FALSE; + } + } + + @RequiredArgsConstructor + public enum DialType { + MANUAL("手"), + INBOUND("进"), + CAMPAIGN("预"); + + @Getter + private final String text; + } + + @RequiredArgsConstructor + public enum CallDirection { + INCOMING("来电"), + OUTGOING("去电"); + + @Getter + private final String text; + } + + @RequiredArgsConstructor + public enum CallType { + INTERNAL("内线"), + INBOUND("进线"), + OUTBOUND("外呼"); + + @Getter + private final String text; + } +} diff --git a/server/src/main/java/com/pudonghot/yo/fsagent/controller/PostCdrController.java b/server/src/main/java/com/pudonghot/yo/fsagent/controller/PostCdrController.java index 5d9755b7..d0330c76 100644 --- a/server/src/main/java/com/pudonghot/yo/fsagent/controller/PostCdrController.java +++ b/server/src/main/java/com/pudonghot/yo/fsagent/controller/PostCdrController.java @@ -1,10 +1,15 @@ package com.pudonghot.yo.fsagent.controller; -import java.util.Map; +import lombok.*; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.pudonghot.yo.model.domain.CallDetailRecordBase; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.beans.factory.annotation.Autowired; +import com.pudonghot.yo.fsagent.service.CallDetailRecordService; +import com.pudonghot.yo.fsagent.controller.request.CdrCtrlrReqDTO; /** * @author Donghuang
@@ -14,10 +19,38 @@ import org.springframework.web.bind.annotation.RequestParam; @Controller public class PostCdrController { + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private CallDetailRecordService callDetailRecordService; + @PostMapping("/fsa/api/cdr/post") - public void postCdr( - @RequestParam - final Map params) { - log.info("Post cdr params: {}", params); + public void postCdr(@RequestParam("cdr") final String cdr) { + log.info("Post cdr params: {}", cdr); + val cdrDTO = readObj(cdr); + + if (Boolean.TRUE.equals(cdrDTO.getIgnore())) { + log.debug("CDR ignored."); + return; + } + + callDetailRecordService.insert(convert(cdrDTO, CallDetailRecordBase.class)); + } + + @SneakyThrows + private CdrCtrlrReqDTO readObj(final String strCdr) { + val jsonNode = objectMapper.readTree(strCdr); + log.info("Json Node [{}].", jsonNode); + val dto = objectMapper.treeToValue( + jsonNode.get("variables"), CdrCtrlrReqDTO.class); + + log.debug("CDR DTO [{}] read.", dto); + return dto; + } + + private T convert(final Object obj, final Class type) { + log.debug("Convert object [{}] to [{}].", obj, type); + return objectMapper.convertValue(obj, type); } } diff --git a/server/src/main/java/com/pudonghot/yo/fsagent/controller/request/CdrCtrlrReqDTO.java b/server/src/main/java/com/pudonghot/yo/fsagent/controller/request/CdrCtrlrReqDTO.java new file mode 100644 index 00000000..0ac62762 --- /dev/null +++ b/server/src/main/java/com/pudonghot/yo/fsagent/controller/request/CdrCtrlrReqDTO.java @@ -0,0 +1,79 @@ +package com.pudonghot.yo.fsagent.controller.request; + +import lombok.Getter; +import lombok.Setter; +import java.util.Date; +import lombok.ToString; +import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.codehaus.jackson.schema.JsonSerializableSchema; + +/** + * @author Donghuang + * @date Sep 08, 2021 10:50:55 + */ +@Setter +@Getter +@ToString +@JsonSerializableSchema +public class CdrCtrlrReqDTO implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonAlias("odbc-cdr-ignore-leg") + private Boolean ignore; + @JsonAlias("x_tenant_id") + private Integer tenantId; + @JsonAlias("x_tenant_code") + private String tenantCode; + @JsonAlias("x_account") + private String account; + @JsonAlias("x_conn_id") + private String connId; + @JsonAlias("x_dial_type") + private String dialType; + @JsonAlias("x_call_type") + private String callType; + @JsonAlias("x_agent_type") + private String agentType; + @JsonAlias("x_campaign_id") + private Integer campaignId; + @JsonAlias("x_case_key") + private String caseKey; + + private String uuid; + @JsonAlias("call_uuid") + private String callUuid; + @JsonAlias("sip_call_id") + private String sipCallId; + @JsonAlias({"caller_id_number", "sip_from_user"}) + private String callerNumber; + @JsonAlias("x_called_number") + private String calledNumber; + @JsonAlias("x_trunk_id") + private Integer trunkId; + @JsonAlias("x_cpn") + private String callingPartyNumber; + @JsonAlias("start_stamp") + @Getter(onMethod_ = @JsonFormat(shape = JsonFormat.Shape.NUMBER)) + @Setter(onMethod_ = @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")) + private Date startStamp; + @JsonAlias("answer_stamp") + @Getter(onMethod_ = @JsonFormat(shape = JsonFormat.Shape.NUMBER)) + @Setter(onMethod_ = @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")) + private Date answerStamp; + @JsonAlias("end_stamp") + @Getter(onMethod_ = @JsonFormat(shape = JsonFormat.Shape.NUMBER)) + @Setter(onMethod_ = @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")) + private Date endStamp; + private Long duration; + private Long mduration; + private Long billsec; + private Long billmsec; + @JsonAlias("endpoint_disposition") + private String endpointDisposition; + @JsonAlias("hangup_cause") + private String hangupCause; + @JsonAlias("sip_hangup_disposition") + private String hangupDisposition; +} diff --git a/server/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelDestroy.java b/server/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelDestroy.java index 8e8fd409..39c523bf 100644 --- a/server/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelDestroy.java +++ b/server/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelDestroy.java @@ -16,7 +16,7 @@ import org.freeswitch.esl.client.transport.event.Event; import com.pudonghot.yo.service.CommonAgentStatusService; import com.pudonghot.yo.service.CommonAgentEventQueueService; import org.springframework.beans.factory.annotation.Autowired; -import com.pudonghot.yo.model.domain.CallDetailRecord.DialType; +import com.pudonghot.yo.model.domain.CallDetailRecordBase.DialType; import static com.pudonghot.yo.model.agentevent.EventType.AgentOther_PhoneRelease; import static com.pudonghot.yo.model.agentevent.EventType.AgentEvent_Customer_Release; diff --git a/server/src/main/java/com/pudonghot/yo/fsagent/service/CallDetailRecordService.java b/server/src/main/java/com/pudonghot/yo/fsagent/service/CallDetailRecordService.java new file mode 100644 index 00000000..20a83a45 --- /dev/null +++ b/server/src/main/java/com/pudonghot/yo/fsagent/service/CallDetailRecordService.java @@ -0,0 +1,17 @@ +package com.pudonghot.yo.fsagent.service; + +import com.pudonghot.yo.model.domain.CallDetailRecordBase; + +/** + * @author Donghuang + * @date Sep 11, 2021 20:27:22 + */ +public interface CallDetailRecordService { + + /** + * insert cdr + * + * @param req req + */ + void insert(CallDetailRecordBase req); +} diff --git a/server/src/main/java/com/pudonghot/yo/fsagent/service/dubbo/impl/CampaignDialServiceImpl.java b/server/src/main/java/com/pudonghot/yo/fsagent/service/dubbo/impl/CampaignDialServiceImpl.java index 8075a3cb..dc127dd6 100644 --- a/server/src/main/java/com/pudonghot/yo/fsagent/service/dubbo/impl/CampaignDialServiceImpl.java +++ b/server/src/main/java/com/pudonghot/yo/fsagent/service/dubbo/impl/CampaignDialServiceImpl.java @@ -103,8 +103,9 @@ public class CampaignDialServiceImpl implements CampaignDialService { LogMDC.setTraceId(uuid); callUuidList.add(uuid); - final List channelVars = Arrays.asList( + val channelVars = Arrays.asList( "x_account=SYSTEM", + "x_agent_type=SYSTEM", "origination_uuid=" + uuid, "sip_invite_call_id=" + uuid, "originate_timeout=30", diff --git a/server/src/main/java/com/pudonghot/yo/fsagent/service/impl/CallDetailRecordServiceImpl.java b/server/src/main/java/com/pudonghot/yo/fsagent/service/impl/CallDetailRecordServiceImpl.java new file mode 100644 index 00000000..e6c19500 --- /dev/null +++ b/server/src/main/java/com/pudonghot/yo/fsagent/service/impl/CallDetailRecordServiceImpl.java @@ -0,0 +1,34 @@ +package com.pudonghot.yo.fsagent.service.impl; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import com.pudonghot.yo.mapper.CallDetailRecordMapper; +import com.pudonghot.yo.mapper.CallDetailRecordAllMapper; +import com.pudonghot.yo.model.domain.CallDetailRecordBase; +import org.springframework.beans.factory.annotation.Autowired; +import com.pudonghot.yo.fsagent.service.CallDetailRecordService; + +/** + * @author Donghuang + * @date Sep 11, 2021 20:32:27 + */ +@Slf4j +@Service +public class CallDetailRecordServiceImpl + implements CallDetailRecordService { + + @Autowired + private CallDetailRecordMapper callDetailRecordMapper; + @Autowired + private CallDetailRecordAllMapper callDetailRecordAllMapper; + + /** + * {@inheritDoc} + */ + @Override + public void insert(final CallDetailRecordBase req) { + log.debug("Insert call detail [{}].", req); + callDetailRecordAllMapper.insert(req); + // callDetailRecordMapper.insert(req); + } +} diff --git a/server/src/main/java/com/pudonghot/yo/fsagent/service/request/CallDetailtRecordCreateServReq.java b/server/src/main/java/com/pudonghot/yo/fsagent/service/request/CallDetailtRecordCreateServReq.java new file mode 100644 index 00000000..ca6e0705 --- /dev/null +++ b/server/src/main/java/com/pudonghot/yo/fsagent/service/request/CallDetailtRecordCreateServReq.java @@ -0,0 +1,46 @@ +package com.pudonghot.yo.fsagent.service.request; + +import lombok.Getter; +import lombok.Setter; +import java.util.Date; +import lombok.ToString; +import java.io.Serializable; + +/** + * @author Donghuang + * @date Sep 08, 2021 10:50:55 + */ +@Setter +@Getter +@ToString +public class CallDetailtRecordCreateServReq implements Serializable { + private static final long serialVersionUID = 1L; + + private Integer tenantId; + private String tenantCode; + private String account; + private String connId; + private String dialType; + private String callType; + private String agentType; + private Integer campaignId; + private String caseKey; + + private String uuid; + private String callUuid; + private String sipCallId; + private String callerNumber; + private String calledNumber; + private Integer trunkId; + private String callingPartyNumber; + private Date startStamp; + private Date answerStamp; + private Date endStamp; + private Long duration; + private Long mduration; + private Long billsec; + private Long billmsec; + private String endpointDisposition; + private String hangupCause; + private String hangupDisposition; +} diff --git a/server/src/main/resources/templates/config/format_cdr.conf.xml b/server/src/main/resources/templates/config/format_cdr.conf.xml index 80b3b7e2..0d888b6d 100644 --- a/server/src/main/resources/templates/config/format_cdr.conf.xml +++ b/server/src/main/resources/templates/config/format_cdr.conf.xml @@ -7,15 +7,15 @@ - - + + - + @@ -80,8 +80,8 @@ - - + + diff --git a/server/src/test/java/com/pudonghot/yo/fsagent/TestDriver.java b/server/src/test/java/com/pudonghot/yo/fsagent/TestDriver.java index 6e1fa479..68a37246 100644 --- a/server/src/test/java/com/pudonghot/yo/fsagent/TestDriver.java +++ b/server/src/test/java/com/pudonghot/yo/fsagent/TestDriver.java @@ -1,9 +1,12 @@ package com.pudonghot.yo.fsagent; import java.io.File; - +import com.fasterxml.jackson.databind.ObjectMapper; import com.pudonghot.yo.fsagent.controller.ConfigController; +import com.pudonghot.yo.fsagent.controller.request.CdrCtrlrReqDTO; +import lombok.val; import org.junit.Test; +import lombok.SneakyThrows; import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.extern.slf4j.Slf4j; @@ -11,6 +14,7 @@ import org.springframework.util.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.time.DateFormatUtils; +import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; /** * @author Donghuang
@@ -79,4 +83,17 @@ public class TestDriver { log.info("Test [{}] result [{}].", host, ConfigController.PATTERN_IP_SIP_HOST.matcher(host).find()); } + + @Test + @SneakyThrows + public void testCdrDTO() { + val strCdr = "{\"core-uuid\":\"73de06b3-7f8d-4db8-8b79-3f1d896528a0\",\"switchname\":\"citic-cc.qinwei.com\",\"channel_data\":{\"state\":\"CS_REPORTING\",\"direction\":\"outbound\",\"state_number\":\"11\",\"flags\":\"0=1;2=1;3=1;38=1;39=1;41=1;44=1;54=1;96=1;113=1;114=1;160=1;166=1\",\"caps\":\"1=1;2=1;3=1;4=1;5=1;6=1;8=1;9=1\"},\"callStats\":{\"audio\":{\"inbound\":{\"raw_bytes\":0,\"media_bytes\":0,\"packet_count\":0,\"media_packet_count\":0,\"skip_packet_count\":0,\"jitter_packet_count\":0,\"dtmf_packet_count\":0,\"cng_packet_count\":0,\"flush_packet_count\":0,\"largest_jb_size\":0,\"jitter_min_variance\":0,\"jitter_max_variance\":0,\"jitter_loss_rate\":0,\"jitter_burst_rate\":0,\"mean_interval\":0,\"flaw_total\":0,\"quality_percentage\":100,\"mos\":4.5},\"outbound\":{\"raw_bytes\":0,\"media_bytes\":0,\"packet_count\":0,\"media_packet_count\":0,\"skip_packet_count\":0,\"dtmf_packet_count\":0,\"cng_packet_count\":0,\"rtcp_packet_count\":0,\"rtcp_octet_count\":0}}},\"variables\":{\"direction\":\"outbound\",\"is_outbound\":\"true\",\"uuid\":\"613c95d1eefe737fcf53dcec\",\"call_uuid\":\"613c95d1eefe737fcf53dcec\",\"session_id\":\"289354\",\"sip_gateway_name\":\"GW000006\",\"sip_profile_name\":\"gateway\",\"video_media_flow\":\"disabled\",\"text_media_flow\":\"disabled\",\"channel_name\":\"sofia/external/13453758701\",\"sip_destination_url\":\"sip:13453758701@172.23.1.189:5060\",\"x_account\":\"SYSTEM\",\"origination_uuid\":\"613c95d1eefe737fcf53dcec\",\"sip_invite_call_id\":\"613c95d1eefe737fcf53dcec\",\"originate_timeout\":\"30\",\"x_logic_role\":\"CALLED\",\"origination_caller_id_number\":\"123456\",\"x_conn_id\":\"613c95d1eefe737fcf53dcec\",\"ignore_early_media\":\"true\",\"x_dial_type\":\"CAMPAIGN\",\"x_call_type\":\"OUTBOUND\",\"x_tenant_id\":\"1\",\"x_tenant_code\":\"CITIC_CC\",\"x_campaign_id\":\"4\",\"x_rec_id\":\"13000646\",\"x_case_key\":\"15799038\",\"x_called_number\":\"13453758701\",\"x_trunk_id\":\"21\",\"x_cpn\":\"123456\",\"originate_early_media\":\"false\",\"rtp_local_sdp_str\":\"v=0\\r\\no=FreeSWITCH 1631331165 1631331166 IN IP4 172.20.23.188\\r\\ns=FreeSWITCH\\r\\nc=IN IP4 172.20.23.188\\r\\nt=0 0\\r\\nm=audio 29300 RTP/AVP 18 8 101\\r\\na=rtpmap:18 G729/8000\\r\\na=fmtp:18 annexb=no\\r\\na=rtpmap:8 PCMA/8000\\r\\na=rtpmap:101 telephone-event/8000\\r\\na=fmtp:101 0-16\\r\\na=ptime:20\\r\\na=sendrecv\\r\\n\",\"sip_outgoing_contact_uri\":\"\",\"sip_req_uri\":\"13453758701@172.23.1.189:5060\",\"sofia_profile_name\":\"external\",\"recovery_profile_name\":\"external\",\"sofia_profile_url\":\"sip:mod_sofia@172.20.23.188:5080\",\"sip_local_network_addr\":\"172.20.23.188\",\"sip_reply_host\":\"172.23.1.189\",\"sip_reply_port\":\"5060\",\"sip_network_ip\":\"172.23.1.189\",\"sip_network_port\":\"5060\",\"sip_user_agent\":\"VOS3000 V2.1.6.00\",\"sip_allow\":\"INVITE, ACK, CANCEL, BYE, OPTIONS, INFO, UPDATE, PRACK\",\"sip_recover_contact\":\"\",\"sip_full_via\":\"SIP/2.0/UDP 172.20.23.188:5080;received=172.20.23.188;rport=5080;branch=z9hG4bK4SN44j7S9tm2F\",\"sip_recover_via\":\"SIP/2.0/UDP 172.20.23.188:5080;received=172.20.23.188;rport=5080;branch=z9hG4bK4SN44j7S9tm2F\",\"sip_full_from\":\";tag=j812ag2204Sre\",\"sip_full_to\":\";tag=615fff901897232c\",\"sip_from_user\":\"4000895558\",\"sip_from_port\":\"5060\",\"sip_from_uri\":\"4000895558@172.23.1.189:5060\",\"sip_from_host\":\"172.23.1.189\",\"sip_to_user\":\"13453758701\",\"sip_to_port\":\"5060\",\"sip_to_uri\":\"13453758701@172.23.1.189:5060\",\"sip_to_host\":\"172.23.1.189\",\"sip_contact_user\":\"13453758701\",\"sip_contact_port\":\"5060\",\"sip_contact_uri\":\"13453758701@172.23.1.189:5060\",\"sip_contact_host\":\"172.23.1.189\",\"sip_to_tag\":\"615fff901897232c\",\"sip_from_tag\":\"j812ag2204Sre\",\"sip_cseq\":\"41126440\",\"sip_call_id\":\"613c95d1eefe737fcf53dcec\",\"switch_r_sdp\":\"v=0\\r\\no=- 37755 37755 IN IP4 172.23.1.189\\r\\ns=VOS3000\\r\\nc=IN IP4 172.23.1.189\\r\\nt=0 0\\r\\nm=audio 12990 RTP/AVP 8 101\\r\\na=rtpmap:8 PCMA/8000\\r\\na=rtpmap:101 telephone-event/8000\\r\\na=fmtp:101 0-15\\r\\n\",\"ep_codec_string\":\"CORE_PCM_MODULE.PCMA@8000h@20i@64000b\",\"rtp_use_codec_string\":\"G729,PCMA\",\"remote_video_media_flow\":\"inactive\",\"remote_text_media_flow\":\"inactive\",\"remote_audio_media_flow\":\"sendrecv\",\"audio_media_flow\":\"sendrecv\",\"rtp_audio_recv_pt\":\"8\",\"rtp_use_codec_name\":\"PCMA\",\"rtp_use_codec_rate\":\"8000\",\"rtp_use_codec_ptime\":\"20\",\"rtp_use_codec_channels\":\"1\",\"rtp_last_audio_codec_string\":\"PCMA@8000h@20i@1c\",\"read_codec\":\"PCMA\",\"original_read_codec\":\"PCMA\",\"read_rate\":\"8000\",\"original_read_rate\":\"8000\",\"write_codec\":\"PCMA\",\"write_rate\":\"8000\",\"dtmf_type\":\"rfc2833\",\"local_media_ip\":\"172.20.23.188\",\"local_media_port\":\"29300\",\"advertised_media_ip\":\"172.20.23.188\",\"rtp_use_timer_name\":\"soft\",\"rtp_use_pt\":\"8\",\"rtp_use_ssrc\":\"1363008937\",\"rtp_2833_send_payload\":\"101\",\"rtp_2833_recv_payload\":\"101\",\"remote_media_ip\":\"172.23.1.189\",\"remote_media_port\":\"12990\",\"endpoint_disposition\":\"EARLY MEDIA\",\"hangup_cause\":\"NO_ANSWER\",\"hangup_cause_q850\":\"19\",\"digits_dialed\":\"none\",\"start_stamp\":\"2021-09-11 19:41:05\",\"profile_start_stamp\":\"2021-09-11 19:41:05\",\"progress_media_stamp\":\"2021-09-11 19:41:06\",\"end_stamp\":\"2021-09-11 19:42:05\",\"start_epoch\":\"1631360465\",\"start_uepoch\":\"1631360465450501\",\"profile_start_epoch\":\"1631360465\",\"profile_start_uepoch\":\"1631360465450501\",\"answer_epoch\":\"0\",\"answer_uepoch\":\"0\",\"bridge_epoch\":\"0\",\"bridge_uepoch\":\"0\",\"last_hold_epoch\":\"0\",\"last_hold_uepoch\":\"0\",\"hold_accum_seconds\":\"0\",\"hold_accum_usec\":\"0\",\"hold_accum_ms\":\"0\",\"resurrect_epoch\":\"0\",\"resurrect_uepoch\":\"0\",\"progress_epoch\":\"0\",\"progress_uepoch\":\"0\",\"progress_media_epoch\":\"1631360466\",\"progress_media_uepoch\":\"1631360466750368\",\"end_epoch\":\"1631360525\",\"end_uepoch\":\"1631360525010322\",\"caller_id\":\"123456\",\"duration\":\"60\",\"billsec\":\"0\",\"progresssec\":\"0\",\"answersec\":\"0\",\"waitsec\":\"0\",\"progress_mediasec\":\"1\",\"flow_billsec\":\"0\",\"mduration\":\"59560\",\"billmsec\":\"0\",\"progressmsec\":\"0\",\"answermsec\":\"0\",\"waitmsec\":\"0\",\"progress_mediamsec\":\"1300\",\"flow_billmsec\":\"0\",\"uduration\":\"59559821\",\"billusec\":\"0\",\"progressusec\":\"0\",\"answerusec\":\"0\",\"waitusec\":\"0\",\"progress_mediausec\":\"1299867\",\"flow_billusec\":\"0\",\"sip_hangup_disposition\":\"send_cancel\",\"sip_invite_failure_status\":\"487\",\"sip_invite_failure_phrase\":\"CANCEL\",\"rtp_audio_in_raw_bytes\":\"0\",\"rtp_audio_in_media_bytes\":\"0\",\"rtp_audio_in_packet_count\":\"0\",\"rtp_audio_in_media_packet_count\":\"0\",\"rtp_audio_in_skip_packet_count\":\"0\",\"rtp_audio_in_jitter_packet_count\":\"0\",\"rtp_audio_in_dtmf_packet_count\":\"0\",\"rtp_audio_in_cng_packet_count\":\"0\",\"rtp_audio_in_flush_packet_count\":\"0\",\"rtp_audio_in_largest_jb_size\":\"0\",\"rtp_audio_in_jitter_min_variance\":\"0.00\",\"rtp_audio_in_jitter_max_variance\":\"0.00\",\"rtp_audio_in_jitter_loss_rate\":\"0.00\",\"rtp_audio_in_jitter_burst_rate\":\"0.00\",\"rtp_audio_in_mean_interval\":\"0.00\",\"rtp_audio_in_flaw_total\":\"0\",\"rtp_audio_in_quality_percentage\":\"100.00\",\"rtp_audio_in_mos\":\"4.50\",\"rtp_audio_out_raw_bytes\":\"0\",\"rtp_audio_out_media_bytes\":\"0\",\"rtp_audio_out_packet_count\":\"0\",\"rtp_audio_out_media_packet_count\":\"0\",\"rtp_audio_out_skip_packet_count\":\"0\",\"rtp_audio_out_dtmf_packet_count\":\"0\",\"rtp_audio_out_cng_packet_count\":\"0\",\"rtp_audio_rtcp_packet_count\":\"0\",\"rtp_audio_rtcp_octet_count\":\"0\"},\"callflow\":[{\"profile_index\":\"1\",\"caller_profile\":{\"username\":\"\",\"dialplan\":\"\",\"caller_id_name\":\"\",\"ani\":\"0000000000\",\"aniii\":\"\",\"caller_id_number\":\"123456\",\"network_addr\":\"172.23.1.189\",\"rdnis\":\"\",\"destination_number\":\"13453758701\",\"uuid\":\"613c95d1eefe737fcf53dcec\",\"source\":\"src/switch_ivr_originate.c\",\"context\":\"default\",\"chan_name\":\"sofia/external/13453758701\"},\"times\":{\"created_time\":\"1631360465450501\",\"profile_created_time\":\"1631360465450501\",\"progress_time\":\"0\",\"progress_media_time\":\"1631360466750368\",\"answered_time\":\"0\",\"bridged_time\":\"0\",\"last_hold_time\":\"0\",\"hold_accum_time\":\"0\",\"hangup_time\":\"1631360525010322\",\"resurrect_time\":\"0\",\"transfer_time\":\"0\"}}]}"; + val objectMapper = new ObjectMapper(); + objectMapper.disable(FAIL_ON_UNKNOWN_PROPERTIES); + val jsonNode = objectMapper.readTree(strCdr); + log.info("Json Node [{}].", jsonNode); + val dto = objectMapper.treeToValue(jsonNode.get("variables"), CdrCtrlrReqDTO.class); + log.info("DTO: {}", dto); + log.info("DTO JSON: {}", objectMapper.writeValueAsString(dto)); + } } diff --git a/start.sh b/start.sh index 74f4a29a..20accde5 100755 --- a/start.sh +++ b/start.sh @@ -24,7 +24,7 @@ WORK_DIR=$(pwd) echo "Work dir [$WORK_DIR]" if [ -z "$1" ]; then - echo 'Usage: ./start.sh module(cms,fsagent...)' + echo 'Usage: ./start.sh module(cms,server)' exit 1 fi