|
|
@@ -0,0 +1,446 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
|
|
|
+ *
|
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
|
+ * modification, are permitted provided that the following conditions are met:
|
|
|
+ *
|
|
|
+ * Redistributions of source code must retain the above copyright notice,
|
|
|
+ * this list of conditions and the following disclaimer.
|
|
|
+ * Redistributions in binary form must reproduce the above copyright
|
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
|
+ * Neither the name of the dreamlu.net developer nor the names of its
|
|
|
+ * contributors may be used to endorse or promote products derived from
|
|
|
+ * this software without specific prior written permission.
|
|
|
+ * Author: Chill 庄骞 (smallchill@163.com)
|
|
|
+ */
|
|
|
+package org.springblade.land.insurance.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|
|
+import io.seata.spring.annotation.GlobalTransactional;
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import org.springblade.client.entity.CorpsAttn;
|
|
|
+import org.springblade.client.entity.CorpsDesc;
|
|
|
+import org.springblade.client.entity.Message;
|
|
|
+import org.springblade.client.feign.ICorpsAttnClient;
|
|
|
+import org.springblade.client.feign.ICorpsDescClient;
|
|
|
+import org.springblade.client.feign.IMessageClient;
|
|
|
+import org.springblade.client.feign.ISerialClient;
|
|
|
+import org.springblade.core.mp.support.Condition;
|
|
|
+import org.springblade.core.mp.support.Query;
|
|
|
+import org.springblade.core.secure.utils.AuthUtil;
|
|
|
+import org.springblade.core.secure.utils.SecureUtil;
|
|
|
+import org.springblade.core.tool.api.R;
|
|
|
+import org.springblade.core.tool.utils.ObjectUtil;
|
|
|
+import org.springblade.finance.dto.ApplyDTO;
|
|
|
+import org.springblade.finance.feign.IFinanceClient;
|
|
|
+import org.springblade.finance.vojo.Acc;
|
|
|
+import org.springblade.finance.vojo.Items;
|
|
|
+import org.springblade.land.constant.LandConst;
|
|
|
+import org.springblade.land.insurance.entity.Insurance;
|
|
|
+import org.springblade.land.insurance.entity.InsuranceFiles;
|
|
|
+import org.springblade.land.insurance.mapper.InsuranceFilesMapper;
|
|
|
+import org.springblade.land.insurance.vo.InsuranceVO;
|
|
|
+import org.springblade.land.insurance.mapper.InsuranceMapper;
|
|
|
+import org.springblade.land.insurance.service.IInsuranceService;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import org.springblade.system.feign.ISysClient;
|
|
|
+import org.springblade.system.user.entity.User;
|
|
|
+import org.springblade.system.user.feign.IUserClient;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.BigInteger;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 陆运保险主表 服务实现类
|
|
|
+ *
|
|
|
+ * @author BladeX
|
|
|
+ * @since 2023-02-15
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@AllArgsConstructor
|
|
|
+public class InsuranceServiceImpl extends ServiceImpl<InsuranceMapper, Insurance> implements IInsuranceService {
|
|
|
+
|
|
|
+ private ISerialClient serialClient;//生成系统编号
|
|
|
+ private final InsuranceFilesMapper filesMapper;//附件明细
|
|
|
+
|
|
|
+ private final ICorpsDescClient corpsDescClient;//客户
|
|
|
+ private final ICorpsAttnClient corpsAttnClient;//客户联系人
|
|
|
+ private final IFinanceClient financeClient;//财务
|
|
|
+ private final ISysClient sysClient;
|
|
|
+ private IUserClient userClient;//获取用户信息
|
|
|
+ private final IMessageClient messageClient;//消息
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 详情
|
|
|
+ *
|
|
|
+ * @param insurance
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Insurance getDetail(Insurance insurance){
|
|
|
+ if (insurance.getId() == null){
|
|
|
+ throw new SecurityException("缺少必要参数");
|
|
|
+ }
|
|
|
+ //获得保险详情
|
|
|
+ Insurance detail = baseMapper.selectById(insurance.getId());
|
|
|
+
|
|
|
+ if (ObjectUtil.isNotEmpty(detail)){
|
|
|
+ //获得附件信息
|
|
|
+ LambdaQueryWrapper<InsuranceFiles> filesLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ filesLambdaQueryWrapper.eq(InsuranceFiles::getIsDeleted, 0)
|
|
|
+ .eq(InsuranceFiles::getTenantId, AuthUtil.getTenantId())
|
|
|
+ .eq(InsuranceFiles::getPid, detail.getId());
|
|
|
+ List<InsuranceFiles> filesList = filesMapper.selectList(filesLambdaQueryWrapper);
|
|
|
+
|
|
|
+ List<InsuranceFiles> fleetList = new ArrayList<>();
|
|
|
+ List<InsuranceFiles> filesOneList = new ArrayList<>();
|
|
|
+ List<InsuranceFiles> filesTwoList = new ArrayList<>();
|
|
|
+ List<InsuranceFiles> filesThreeList = new ArrayList<>();
|
|
|
+ if (ObjectUtil.isNotEmpty(filesList)){
|
|
|
+ filesList.forEach(e -> {
|
|
|
+ if (ObjectUtil.isNotEmpty(e.getFilesType())){
|
|
|
+ if ("0".equals(e.getFilesType())){//车队附件
|
|
|
+ fleetList.add(e);
|
|
|
+ } else if ("1".equals(e.getFilesType())){//保费1
|
|
|
+ filesOneList.add(e);
|
|
|
+ } else if ("2".equals(e.getFilesType())){//保费2
|
|
|
+ filesTwoList.add(e);
|
|
|
+ } else if ("3".equals(e.getFilesType())){//保费3
|
|
|
+ filesThreeList.add(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ detail.setFleetList(fleetList);
|
|
|
+ detail.setFilesOneList(filesOneList);
|
|
|
+ detail.setFilesTwoList(filesTwoList);
|
|
|
+ detail.setFilesThreeList(filesThreeList);
|
|
|
+ }
|
|
|
+
|
|
|
+ return detail;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分页
|
|
|
+ *
|
|
|
+ * @param insurance
|
|
|
+ * @param query
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public IPage<Insurance> getList(Insurance insurance, Query query){
|
|
|
+ LambdaQueryWrapper<Insurance> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ lambdaQueryWrapper.like(ObjectUtil.isNotEmpty(insurance.getCarNumberName()), Insurance::getCarNumberId, insurance.getCarNumberName())//车号
|
|
|
+ .eq(ObjectUtil.isNotEmpty(insurance.getStatus()), Insurance::getStatus, insurance.getStatus());//状态
|
|
|
+
|
|
|
+ //根据当前登录人获得客户联系人
|
|
|
+ CorpsAttn corpsAttn = corpsAttnClient.getUser(AuthUtil.getUserId());
|
|
|
+ if (ObjectUtil.isNotEmpty(corpsAttn)){
|
|
|
+ //根据客户联系人获得客户
|
|
|
+ CorpsDesc corpsDesc = corpsDescClient.getCorpId(corpsAttn.getPid());
|
|
|
+ if (ObjectUtil.isNotEmpty(corpsDesc)){
|
|
|
+ String role = AuthUtil.getUserRole();
|
|
|
+ if (role.contains(LandConst.ROLE_CD)){//车队只能看自己车队
|
|
|
+ lambdaQueryWrapper.eq(Insurance::getFleetId, corpsDesc.getId());//车队
|
|
|
+ }else if (role.contains(LandConst.ROLE_BXGS)){//保险公司只能看自己公司
|
|
|
+ lambdaQueryWrapper.eq(Insurance::getInsuranceCompanyId, corpsDesc.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ IPage<Insurance> pages = baseMapper.selectPage(Condition.getPage(query), lambdaQueryWrapper);
|
|
|
+
|
|
|
+ return pages;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自定义分页
|
|
|
+ *
|
|
|
+ * @param insurance
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public IPage<InsuranceVO> selectInsurancePage(IPage<InsuranceVO> page, InsuranceVO insurance) {
|
|
|
+ return page.setRecords(baseMapper.selectInsurancePage(page, insurance));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增或修改
|
|
|
+ *
|
|
|
+ * @param insurance
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ @GlobalTransactional(rollbackFor = Exception.class, timeoutMills = 12000000)
|
|
|
+ public Insurance add(Insurance insurance){
|
|
|
+ if (insurance.getId() == null){
|
|
|
+ //获取系统编号
|
|
|
+ R billNo = new R();
|
|
|
+
|
|
|
+ billNo = serialClient.getBillNo("LYBX", "LYBX", "LYBX");
|
|
|
+ if (!billNo.isSuccess()) {
|
|
|
+ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
|
|
+ throw new Error("生成系统编号失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ insurance.setSysNo(billNo.getData().toString());
|
|
|
+ insurance.setTenantId(AuthUtil.getTenantId());
|
|
|
+ insurance.setCreateUser(AuthUtil.getUserId());
|
|
|
+ insurance.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
|
|
|
+ insurance.setCreateTime(new Date());
|
|
|
+ insurance.setStatus(0);
|
|
|
+ insurance.setStatusName("未获取");
|
|
|
+ baseMapper.insert(insurance);
|
|
|
+ }else {
|
|
|
+ insurance.setUpdateTime(new Date());
|
|
|
+ insurance.setUpdateUser(AuthUtil.getUserId());
|
|
|
+ baseMapper.updateById(insurance);
|
|
|
+ }
|
|
|
+
|
|
|
+ //车队附件
|
|
|
+ List<InsuranceFiles> fleetList = insurance.getFleetList();
|
|
|
+ saveFile(fleetList, insurance.getId());
|
|
|
+ insurance.setFleetList(fleetList);
|
|
|
+ //保费1附件
|
|
|
+ List<InsuranceFiles> filesOneList = insurance.getFilesOneList();
|
|
|
+ saveFile(filesOneList, insurance.getId());
|
|
|
+ insurance.setFilesOneList(filesOneList);
|
|
|
+ //保费2附件
|
|
|
+ List<InsuranceFiles> filesTwoList = insurance.getFilesTwoList();
|
|
|
+ saveFile(filesTwoList, insurance.getId());
|
|
|
+ insurance.setFleetList(filesTwoList);
|
|
|
+ //保费3附件
|
|
|
+ List<InsuranceFiles> filesThreeList = insurance.getFilesThreeList();
|
|
|
+ saveFile(filesThreeList, insurance.getId());
|
|
|
+ insurance.setFleetList(filesThreeList);
|
|
|
+
|
|
|
+ return insurance;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 申请通过或驳回
|
|
|
+ *
|
|
|
+ * @param insurance
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Insurance passCheck(Insurance insurance){
|
|
|
+ if (insurance.getCheckFlag() == null || insurance.getId() == null){
|
|
|
+ throw new SecurityException("缺少必要参数");
|
|
|
+ }
|
|
|
+ //获得保险详情
|
|
|
+ Insurance detail = baseMapper.selectById(insurance.getId());
|
|
|
+
|
|
|
+ if (ObjectUtil.isNotEmpty(detail)){
|
|
|
+ if (insurance.getCheckFlag() == 1){//通过
|
|
|
+ if (insurance.getStatus() == 0){
|
|
|
+ insurance.setStatus(1);
|
|
|
+ insurance.setStatusName("未确认");
|
|
|
+ }else if (insurance.getStatus() == 1){
|
|
|
+ insurance.setStatus(2);
|
|
|
+ insurance.setStatusName("已确认");
|
|
|
+ }else if (insurance.getStatus() == 2){//保费提交重新保存附件
|
|
|
+ //保费1附件
|
|
|
+ List<InsuranceFiles> filesOne = insurance.getFilesOneList();
|
|
|
+ saveFile(filesOne, insurance.getId());
|
|
|
+ //保费2附件
|
|
|
+ List<InsuranceFiles> filesTwo = insurance.getFilesTwoList();
|
|
|
+ saveFile(filesTwo, insurance.getId());
|
|
|
+ //保费3附件
|
|
|
+ List<InsuranceFiles> filesThree = insurance.getFilesThreeList();
|
|
|
+ saveFile(filesThree, insurance.getId());
|
|
|
+
|
|
|
+ insurance.setStatus(3);
|
|
|
+ insurance.setStatusName("未受理");
|
|
|
+ }else if (insurance.getStatus() == 3){
|
|
|
+ insurance.setStatus(4);
|
|
|
+ insurance.setStatusName("已受理");
|
|
|
+ }else if (insurance.getStatus() == 4){
|
|
|
+ //生成对账明细
|
|
|
+ paymentApply(insurance);
|
|
|
+ insurance.setStatus(5);
|
|
|
+ insurance.setStatusName("未签单");
|
|
|
+ }else if (insurance.getStatus() == 5){
|
|
|
+ insurance.setStatus(6);
|
|
|
+ insurance.setStatusName("已完成");
|
|
|
+ }
|
|
|
+ }else if (insurance.getCheckFlag() == 2){//驳回
|
|
|
+ if (insurance.getStatus() == 0){
|
|
|
+ throw new SecurityException("订单未获取报价撤销失败");
|
|
|
+ }else if (insurance.getStatus() == 1){
|
|
|
+ insurance.setStatus(0);
|
|
|
+ insurance.setStatusName("未获取");
|
|
|
+ }else if (insurance.getStatus() == 2){
|
|
|
+ insurance.setStatus(1);
|
|
|
+ insurance.setStatusName("未确认");
|
|
|
+ }else if (insurance.getStatus() == 3){
|
|
|
+ insurance.setStatus(2);
|
|
|
+ insurance.setStatusName("已确认");
|
|
|
+ }else if (insurance.getStatus() == 4){
|
|
|
+ //撤销验证账单是否已结算
|
|
|
+ revoke(insurance);
|
|
|
+ insurance.setStatus(3);
|
|
|
+ insurance.setStatusName("未受理");
|
|
|
+ }else if (insurance.getStatus() == 5){
|
|
|
+ insurance.setStatus(4);
|
|
|
+ insurance.setStatusName("已受理");
|
|
|
+ }else if (insurance.getStatus() == 6){
|
|
|
+ insurance.setStatus(5);
|
|
|
+ insurance.setStatusName("未签单");
|
|
|
+ }
|
|
|
+ }else if (insurance.getCheckFlag() == 3){
|
|
|
+ insurance.setStatus(7);
|
|
|
+ insurance.setStatusName("弃保");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ baseMapper.updateById(insurance);
|
|
|
+
|
|
|
+ return insurance;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成账单明细
|
|
|
+ */
|
|
|
+ public void paymentApply(Insurance detail){
|
|
|
+
|
|
|
+ //账单数据
|
|
|
+ ApplyDTO applyDTO = new ApplyDTO();
|
|
|
+ applyDTO.setBillType("申请");
|
|
|
+ applyDTO.setTradeType("LYBX");
|
|
|
+ applyDTO.setBelongCompany(detail.getFleetName());
|
|
|
+
|
|
|
+ List<Items> itemsList = new ArrayList<>();
|
|
|
+
|
|
|
+ Items items = new Items();
|
|
|
+ items.setSrcFeesType("申请");
|
|
|
+ items.setItemName("保险");
|
|
|
+ items.setItemType("LYBX");
|
|
|
+ //账单数据
|
|
|
+ if (ObjectUtil.isNotEmpty(detail.getDisplay())){
|
|
|
+ if (detail.getDisplay() == 1){
|
|
|
+ if (ObjectUtil.isNotEmpty(detail.getActualPremiumOne())){
|
|
|
+ items.setAmount(detail.getActualPremiumOne());
|
|
|
+ }else {
|
|
|
+ items.setAmount(new BigDecimal(BigInteger.ZERO));
|
|
|
+ }
|
|
|
+ }else if (detail.getDisplay() == 2){
|
|
|
+ if (ObjectUtil.isNotEmpty(detail.getActualPremiumTwo())){
|
|
|
+ items.setAmount(detail.getActualPremiumTwo());
|
|
|
+ }else {
|
|
|
+ items.setAmount(new BigDecimal(BigInteger.ZERO));
|
|
|
+ }
|
|
|
+ }else if (detail.getDisplay() == 3){
|
|
|
+ if (ObjectUtil.isNotEmpty(detail.getActualPremiumThree())){
|
|
|
+ items.setAmount(detail.getActualPremiumThree());
|
|
|
+ }else {
|
|
|
+ items.setAmount(new BigDecimal(BigInteger.ZERO));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ items.setAmount(new BigDecimal(BigInteger.ZERO));
|
|
|
+ }
|
|
|
+ items.setSrcOrderno(detail.getSysNo());//来源订单号
|
|
|
+ items.setSrcParentId(detail.getId());//来源主表id
|
|
|
+ items.setSrcType(12);//结算标识
|
|
|
+ items.setTradeType("LYBX");//系统类别
|
|
|
+ items.setPlateNo(detail.getCarNumberName());//车号
|
|
|
+ items.setCorpId(detail.getInsuranceCompanyId());//保险公司
|
|
|
+ items.setRemarks(detail.getRemark());//备注
|
|
|
+ items.setStockTime(detail.getBusinessDate());//业务日期
|
|
|
+ itemsList.add(items);
|
|
|
+ applyDTO.setItemsList(itemsList);
|
|
|
+
|
|
|
+ if (CollectionUtils.isNotEmpty(itemsList)) {
|
|
|
+ //生成账单
|
|
|
+ R paymentApply = financeClient.paymentApplyBoxTube(applyDTO);
|
|
|
+ if (!paymentApply.isSuccess()) {
|
|
|
+ throw new RuntimeException(paymentApply.getMsg());
|
|
|
+ }
|
|
|
+ //给角色为财务的人发送消息
|
|
|
+ R<String> clientDeptIds = sysClient.getRoleIds(SecureUtil.getTenantId(), "财务");
|
|
|
+ if (clientDeptIds.isSuccess() && StringUtils.isNotBlank(clientDeptIds.getData())) {
|
|
|
+ R<List<User>> userList = userClient.listUserByRoleId(Long.valueOf(clientDeptIds.getData()));
|
|
|
+ if (userList.isSuccess() && CollectionUtils.isNotEmpty(userList.getData())) {
|
|
|
+ for (User datum : userList.getData()) {
|
|
|
+ //循环发送消息
|
|
|
+ Message sendMessage = new Message();
|
|
|
+ sendMessage.setParameter(String.valueOf(detail.getId()));
|
|
|
+ sendMessage.setUserName(AuthUtil.getUserName());
|
|
|
+ sendMessage.setUserId(AuthUtil.getUserId());
|
|
|
+ sendMessage.setToUserId(datum.getId());
|
|
|
+ sendMessage.setToUserName(datum.getName());
|
|
|
+ sendMessage.setMessageType(1);
|
|
|
+ sendMessage.setTenantId(AuthUtil.getTenantId());
|
|
|
+ sendMessage.setCreateUser(AuthUtil.getUserId());
|
|
|
+ sendMessage.setCreateTime(new Date());
|
|
|
+ sendMessage.setMessageBody("保险业务" + detail.getSysNo() + "车队确认投保,请查看");
|
|
|
+ R save = messageClient.save(sendMessage);
|
|
|
+ if (!save.isSuccess()) {
|
|
|
+ throw new SecurityException("发送消息失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 撤销账单
|
|
|
+ */
|
|
|
+ public void revoke(Insurance insurance){
|
|
|
+ //获取账单信息
|
|
|
+ Acc acc = new Acc();
|
|
|
+ acc.setSrcParentId(insurance.getId());
|
|
|
+ acc.setBillType("申请");
|
|
|
+ acc.setTradeType("LYBX");
|
|
|
+ acc.setSrcType(12);
|
|
|
+ R<List<Acc>> r = financeClient.getAccListByCondition(acc);
|
|
|
+ if (r.isSuccess() && ObjectUtils.isNotNull(r.getData())) {
|
|
|
+ for (Acc acc_ : r.getData()) {
|
|
|
+ //判断是否有结算 true 不允许撤销审核 false 删除账单信息并撤销审核
|
|
|
+ if (!acc_.getSettlementAmount().equals(new BigDecimal("0.00"))) {
|
|
|
+ throw new SecurityException("保险已结算,不允许撤销");
|
|
|
+ } else {
|
|
|
+ financeClient.remove(acc_.getId() + "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存附件明细
|
|
|
+ */
|
|
|
+ private void saveFile(List<InsuranceFiles> filesList, Long id){
|
|
|
+ if (ObjectUtils.isNotNull(filesList) && filesList.size() > 0) {
|
|
|
+ for (InsuranceFiles item : filesList) {
|
|
|
+ if (item.getId() == null) {
|
|
|
+ item.setCreateUser(AuthUtil.getUserId());
|
|
|
+ item.setCreateTime(new Date());
|
|
|
+ item.setTenantId(AuthUtil.getTenantId());
|
|
|
+ item.setPid(id);
|
|
|
+ filesMapper.insert(item);
|
|
|
+ } else {
|
|
|
+ item.setUpdateUser(AuthUtil.getUserId());
|
|
|
+ item.setUpdateTime(new Date());
|
|
|
+ item.setPid(id);
|
|
|
+ filesMapper.updateById(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|