From b2af5f5f3360cd95674d828b83dc696d1f5ff3fa Mon Sep 17 00:00:00 2001
From: maven <2163098428@qq.com>
Date: 星期二, 11 十一月 2025 18:02:09 +0800
Subject: [PATCH] yys  1.仓储物流增加分类管理      2.仓储物流分类管理导出接口      4.新疆生产管控定制化

---
 src/main/java/com/ruoyi/production/service/impl/SalesLedgerSchedulingServiceImpl.java |  110 +++++++++++++++++++++
 src/main/java/com/ruoyi/production/controller/SalesLedgerSchedulingController.java    |   41 ++++++++
 src/main/java/com/ruoyi/production/pojo/SpeculativeTradingInfo.java                   |   81 ++++++++++++++++
 src/main/resources/mapper/production/SalesLedgerSchedulingMapper.xml                  |    1 
 src/main/java/com/ruoyi/production/dto/SalesLedgerSchedulingDto.java                  |    6 +
 src/main/java/com/ruoyi/production/mapper/SpeculativeTradingInfoMapper.java           |   11 ++
 src/main/java/com/ruoyi/production/pojo/SalesLedgerScheduling.java                    |    6 +
 src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java                            |    6 +
 src/main/java/com/ruoyi/production/dto/ProductionDispatchAddDto.java                  |   11 ++
 src/main/java/com/ruoyi/basic/pojo/ProductModel.java                                  |    6 +
 10 files changed, 278 insertions(+), 1 deletions(-)

diff --git a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
index 335dd3a..5e7496a 100644
--- a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
+++ b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -39,6 +39,12 @@
     @Excel(name = "鍗曚綅")
     private String unit;
 
+    /**
+     * 鐢熶骇鐐掓満
+     */
+    @Excel(name = "鐢熶骇鐐掓満")
+    private String speculativeTradingName;
+
     @ApiModelProperty(value = "绉熸埛ID")
     @TableField(fill = FieldFill.INSERT)
     private Long tenantId;
diff --git a/src/main/java/com/ruoyi/production/controller/SalesLedgerSchedulingController.java b/src/main/java/com/ruoyi/production/controller/SalesLedgerSchedulingController.java
index 5ca3bc2..fd4b2b2 100644
--- a/src/main/java/com/ruoyi/production/controller/SalesLedgerSchedulingController.java
+++ b/src/main/java/com/ruoyi/production/controller/SalesLedgerSchedulingController.java
@@ -12,11 +12,14 @@
 import com.ruoyi.production.dto.ProductionDispatchAddDto;
 import com.ruoyi.production.dto.SalesLedgerSchedulingDto;
 import com.ruoyi.production.dto.SalesLedgerSchedulingProcessDto;
+import com.ruoyi.production.mapper.SpeculativeTradingInfoMapper;
+import com.ruoyi.production.pojo.SpeculativeTradingInfo;
 import com.ruoyi.production.service.impl.SalesLedgerSchedulingServiceImpl;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
@@ -35,6 +38,44 @@
     private SalesLedgerSchedulingServiceImpl salesLedgerSchedulingService;
 
 
+    @Autowired
+    private SpeculativeTradingInfoMapper speculativeTradingInfoMapper;
+
+    @GetMapping("/list")
+    @Log(title = "鐢熶骇绠$悊-鐢熶骇娲惧伐-鐐掓満淇℃伅", businessType = BusinessType.OTHER)
+    @ApiOperation("鐢熶骇绠$悊-鐢熶骇娲惧伐-鐐掓満淇℃伅")
+    public AjaxResult list() {
+        List<SpeculativeTradingInfo> result = speculativeTradingInfoMapper.selectList(null);
+        result.forEach(item -> {
+            item.setCurrentWorkLoad(salesLedgerSchedulingService.getSchedulingNumBySpeculativeTradingName(item.getName()));
+            item.setVacant(item.getWorkLoad().subtract(item.getCurrentWorkLoad()));
+        });
+        return AjaxResult.success(result);
+    }
+
+    @PostMapping("/addSpeculatTrading")
+    @Log(title = "鐢熶骇绠$悊-鐢熶骇娲惧伐-娣诲姞鐐掓満淇℃伅", businessType = BusinessType.INSERT)
+    @ApiOperation("鐢熶骇绠$悊-鐢熶骇娲惧伐-娣诲姞鐐掓満淇℃伅")
+    public AjaxResult addSpeculatTrading(@RequestBody List<SpeculativeTradingInfo> speculativeTradingInfo) {
+        if(CollectionUtils.isEmpty(speculativeTradingInfo)) return AjaxResult.error("鏁版嵁缁勪笉鑳戒负绌�");
+        speculativeTradingInfo.forEach(item -> {
+            speculativeTradingInfoMapper.insert(item);
+        });
+        return AjaxResult.success("娣诲姞鐐掓満淇℃伅鎴愬姛");
+    }
+
+    @PostMapping("/updateSpeculatTrading")
+    @Log(title = "鐢熶骇绠$悊-鐢熶骇娲惧伐-淇敼鐐掓満淇℃伅", businessType = BusinessType.UPDATE)
+    @ApiOperation("鐢熶骇绠$悊-鐢熶骇娲惧伐-淇敼鐐掓満淇℃伅")
+    public AjaxResult updateSpeculatTrading(@RequestBody List<SpeculativeTradingInfo> speculativeTradingInfo) {
+        if(CollectionUtils.isEmpty(speculativeTradingInfo)) return AjaxResult.error("鏁版嵁缁勪笉鑳戒负绌�");
+        speculativeTradingInfo.forEach(item -> {
+            speculativeTradingInfoMapper.updateById(item);
+        });
+        return AjaxResult.success("淇敼鐐掓満淇℃伅鎴愬姛");
+    }
+
+
     @GetMapping("/listPage")
     @Log(title = "鐢熶骇绠$悊-鐢熶骇璁㈠崟-鍒嗛〉鏌ヨ", businessType = BusinessType.OTHER)
     @ApiOperation("鐢熶骇绠$悊-鐢熶骇璁㈠崟-鍒嗛〉鏌ヨ")
diff --git a/src/main/java/com/ruoyi/production/dto/ProductionDispatchAddDto.java b/src/main/java/com/ruoyi/production/dto/ProductionDispatchAddDto.java
index e78d868..6385f0f 100644
--- a/src/main/java/com/ruoyi/production/dto/ProductionDispatchAddDto.java
+++ b/src/main/java/com/ruoyi/production/dto/ProductionDispatchAddDto.java
@@ -1,5 +1,6 @@
 package com.ruoyi.production.dto;
 
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -38,4 +39,14 @@
     @ApiModelProperty(value = "鎺掍骇鏃ユ湡")
     private String schedulingDate;
 
+    /**
+     * 鐢熶骇鐐掓満
+     */
+    private String speculativeTradingName;
+
+    /**
+     * 瑙勬牸鍨嬪彿
+     */
+    private String specificationModel;
+
 }
diff --git a/src/main/java/com/ruoyi/production/dto/SalesLedgerSchedulingDto.java b/src/main/java/com/ruoyi/production/dto/SalesLedgerSchedulingDto.java
index 4e606a1..1acb484 100644
--- a/src/main/java/com/ruoyi/production/dto/SalesLedgerSchedulingDto.java
+++ b/src/main/java/com/ruoyi/production/dto/SalesLedgerSchedulingDto.java
@@ -28,6 +28,12 @@
     private Long salesLedgerId;
 
     /**
+     * 鐢熶骇鐐掓満
+     */
+    @Excel(name = "鐢熶骇鐐掓満")
+    private String speculativeTradingName;
+
+    /**
      * 閿�鍞悎鍚屽彿
      */
     @Excel(name = "閿�鍞悎鍚屽彿")
diff --git a/src/main/java/com/ruoyi/production/mapper/SpeculativeTradingInfoMapper.java b/src/main/java/com/ruoyi/production/mapper/SpeculativeTradingInfoMapper.java
new file mode 100644
index 0000000..21d4a11
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/mapper/SpeculativeTradingInfoMapper.java
@@ -0,0 +1,11 @@
+package com.ruoyi.production.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.production.pojo.SpeculativeTradingInfo;
+
+/**
+ * @author :yys
+ * @date : 2025/11/11 15:40
+ */
+public interface SpeculativeTradingInfoMapper extends BaseMapper<SpeculativeTradingInfo> {
+}
diff --git a/src/main/java/com/ruoyi/production/pojo/SalesLedgerScheduling.java b/src/main/java/com/ruoyi/production/pojo/SalesLedgerScheduling.java
index 937ff7f..e50d2d1 100644
--- a/src/main/java/com/ruoyi/production/pojo/SalesLedgerScheduling.java
+++ b/src/main/java/com/ruoyi/production/pojo/SalesLedgerScheduling.java
@@ -1,6 +1,7 @@
 package com.ruoyi.production.pojo;
 
 import com.baomidou.mybatisplus.annotation.*;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
 import lombok.Builder;
 import lombok.Data;
 
@@ -38,6 +39,11 @@
     private Long schedulingUserId;
 
     /**
+     * 鐢熶骇鐐掓満
+     */
+    private String speculativeTradingName;
+
+    /**
      * 娲惧伐浜哄悕绉�
      */
     private String schedulingUserName;
diff --git a/src/main/java/com/ruoyi/production/pojo/SpeculativeTradingInfo.java b/src/main/java/com/ruoyi/production/pojo/SpeculativeTradingInfo.java
new file mode 100644
index 0000000..4ac0567
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/pojo/SpeculativeTradingInfo.java
@@ -0,0 +1,81 @@
+package com.ruoyi.production.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * @author :yys
+ * @date : 2025/11/11 15:38
+ */
+@TableName("speculative_trading_info")
+@Data
+public class SpeculativeTradingInfo {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 鐐掓満鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 鐐掓満宸ヤ綔閲�(鍗曚綅kg)
+     */
+    private BigDecimal workLoad;
+
+
+    /**
+     * 鎺掑簭
+     */
+    private Integer sort;
+
+    /**
+     * 鐐掓満姝e湪宸ヤ綔閲�(鍗曚綅kg)
+     */
+    @TableField(exist = false)
+    private BigDecimal currentWorkLoad;
+
+    /**
+     * 鐐掓満绌轰綑宸ヤ綔閲�(鍗曚綅kg)
+     */
+    @TableField(exist = false)
+    private BigDecimal vacant;
+
+    /**
+     * 鍒涘缓鑰�
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼鑰�
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    /**
+     * 绉熸埛ID
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long tenantId;
+
+
+}
diff --git a/src/main/java/com/ruoyi/production/service/impl/SalesLedgerSchedulingServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/SalesLedgerSchedulingServiceImpl.java
index 0be634b..0bfe363 100644
--- a/src/main/java/com/ruoyi/production/service/impl/SalesLedgerSchedulingServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/SalesLedgerSchedulingServiceImpl.java
@@ -5,15 +5,18 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto;
 import com.ruoyi.production.dto.*;
 import com.ruoyi.production.mapper.SalesLedgerSchedulingMapper;
 import com.ruoyi.production.mapper.SalesLedgerWorkMapper;
+import com.ruoyi.production.mapper.SpeculativeTradingInfoMapper;
 import com.ruoyi.production.pojo.SalesLedgerScheduling;
 import com.ruoyi.production.pojo.SalesLedgerWork;
+import com.ruoyi.production.pojo.SpeculativeTradingInfo;
 import com.ruoyi.production.service.SalesLedgerSchedulingService;
 import com.ruoyi.project.system.domain.SysUser;
 import com.ruoyi.project.system.mapper.SysUserMapper;
+import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
+import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
@@ -25,8 +28,11 @@
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 /**
@@ -95,13 +101,46 @@
 
     private final SysUserMapper sysUserMapper;
 
+    private final SpeculativeTradingInfoMapper speculativeTradingInfoMapper;
+
     @Override
     public int productionDispatch(ProductionDispatchAddDto productionDispatchAddDto) {
         SysUser sysUser = sysUserMapper.selectUserById(productionDispatchAddDto.getSchedulingUserId());
         if(sysUser == null) throw new RuntimeException("鎺掍骇浜轰笉瀛樺湪");
+        // 鑾峰彇绌轰綑鐐掓満
+        String[] split = productionDispatchAddDto.getSpeculativeTradingName().split(",");
+        if(split != null && split.length == 0){
+            throw new RuntimeException("鐢熶骇鐐掓満涓嶈兘涓虹┖");
+        }
+        List<SpeculativeTradingInfo> speculativeTradingInfos = speculativeTradingInfoMapper.selectList(new LambdaQueryWrapper<SpeculativeTradingInfo>()
+                .in(SpeculativeTradingInfo::getName, Arrays.asList(split))
+                .orderByAsc(SpeculativeTradingInfo::getSort));
+        if(CollectionUtils.isEmpty(speculativeTradingInfos)){
+            throw new RuntimeException("鏃犵┖浣欑倰鏈�,璇锋鏌ョ倰鏈鸿〃");
+        }
+        AtomicReference<String> name = new AtomicReference<>("");  //闇�瑕佺粦瀹氱殑鐐掓満
+        //閫氳繃瑙勬牸鍨嬪彿鍜屾帓浜ф暟閲忚绠楁湰娆$敓浜т骇閲�
+        String[] split1 = productionDispatchAddDto.getSpecificationModel().split("\\*");
+        if(split1.length != 2) throw new RuntimeException("瑙勬牸鍨嬪彿鏍煎紡閿欒");
+        // 鏈鐢熶骇浜ч噺
+        BigDecimal productionNum = new BigDecimal(split1[0])
+                .multiply(new BigDecimal(split1[1]).multiply(productionDispatchAddDto.getSchedulingNum()));
+        // 澶氫釜鐐掓満鎯呭喌
+        if(speculativeTradingInfos.size() > 1){
+            speculativeTradingInfos.forEach(item ->{
+                // 鑾峰彇璇ョ倰鏈烘鍦ㄦ帓浜ч噺
+                BigDecimal schedulingNumBySpeculativeTradingName = getSchedulingNumBySpeculativeTradingName(item.getName());
+                // 濡傛灉璇ョ倰鏈烘�婚噺 - 姝e湪鎺掍骇閲� >=鏈鐢熶骇浜ч噺灏卞垎閰嶆鐐掓満
+                if(item.getWorkLoad().subtract(schedulingNumBySpeculativeTradingName).compareTo(productionNum) >= 0){
+                    name.set(item.getName());
+                }
+            });
+        }
+        if(name.get().isEmpty()) throw new RuntimeException("鏃犵┖浣欑倰鏈�,璇锋鏌ョ倰鏈鸿〃");
         SalesLedgerScheduling salesLedgerScheduling = SalesLedgerScheduling.builder()
                 .salesLedgerId(productionDispatchAddDto.getSalesLedgerId())
                 .salesLedgerProductId(productionDispatchAddDto.getSalesLedgerProductId())
+                .speculativeTradingName(name.get())
                 .schedulingUserId(productionDispatchAddDto.getSchedulingUserId())
                 .schedulingUserName(sysUser.getNickName())
                 .schedulingNum(productionDispatchAddDto.getSchedulingNum())
@@ -111,6 +150,75 @@
         return salesLedgerSchedulingMapper.insert(salesLedgerScheduling);
     }
 
+    private final SalesLedgerProductMapper salesLedgerProductMapper;
+
+    /**
+     *閫氳繃鐐掓満鍚嶇О鑾峰彇褰撳ぉ姝e湪鎺掍骇閲�
+     * @return
+     */
+    public BigDecimal getSchedulingNumBySpeculativeTradingName(String speculativeTradingName){
+        LambdaQueryWrapper<SalesLedgerScheduling> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SalesLedgerScheduling::getSpeculativeTradingName, speculativeTradingName)
+                .eq(SalesLedgerScheduling::getSchedulingDate, LocalDate.now());
+        List<SalesLedgerScheduling> salesLedgerSchedulings = salesLedgerSchedulingMapper.selectList(queryWrapper);
+        if(CollectionUtils.isEmpty(salesLedgerSchedulings)){
+            return BigDecimal.ZERO;
+        }
+        List<Long> collect = salesLedgerSchedulings.stream().map(SalesLedgerScheduling::getSalesLedgerProductId).collect(Collectors.toList());
+        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
+                .in(SalesLedgerProduct::getId, collect));
+        if(CollectionUtils.isEmpty(salesLedgerProducts)) return BigDecimal.ZERO;
+        AtomicInteger totalNum = new AtomicInteger(0); //鎬绘暟
+        salesLedgerSchedulings.forEach(item ->{
+            List<SalesLedgerProduct> collect1 = salesLedgerProducts.stream()
+                    .filter(j -> j.getId().equals(item.getSalesLedgerProductId()))
+                    .collect(Collectors.toList());
+            if(!CollectionUtils.isEmpty(collect1)){
+                SalesLedgerProduct salesLedgerProduct = collect1.get(0);
+                // 鏍规嵁浜у搧瑙勬牸 * 鎺掍骇鏁伴噺 鑾峰彇鏈鐢熶骇浜ч噺骞剁疮璁�
+                String[] split = salesLedgerProduct.getSpecificationModel().split("\\*");
+                BigDecimal productionNum = new BigDecimal(split[0])
+                        .multiply(new BigDecimal(split[1]).multiply(item.getSchedulingNum()));
+                totalNum.addAndGet(productionNum.intValue());
+            }
+        });
+        return new BigDecimal(totalNum.get());
+    }
+
+
+    /**
+     *閫氳繃鎵归噺鐐掓満鍚嶇О鑾峰彇褰撳ぉ姝e湪鎺掍骇閲�
+     * @return
+     */
+    public BigDecimal getSchedulingNumBySpeculativeTradingNameList(List<String> speculativeTradingName){
+        LambdaQueryWrapper<SalesLedgerScheduling> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.in(SalesLedgerScheduling::getSpeculativeTradingName, speculativeTradingName)
+                .eq(SalesLedgerScheduling::getSchedulingDate, LocalDate.now());
+        List<SalesLedgerScheduling> salesLedgerSchedulings = salesLedgerSchedulingMapper.selectList(queryWrapper);
+        if(CollectionUtils.isEmpty(salesLedgerSchedulings)){
+            return BigDecimal.ZERO;
+        }
+        List<Long> collect = salesLedgerSchedulings.stream().map(SalesLedgerScheduling::getSalesLedgerProductId).collect(Collectors.toList());
+        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
+                .in(SalesLedgerProduct::getId, collect));
+        if(CollectionUtils.isEmpty(salesLedgerProducts)) return BigDecimal.ZERO;
+        AtomicInteger totalNum = new AtomicInteger(0); //鎬绘暟
+        salesLedgerSchedulings.forEach(item ->{
+            List<SalesLedgerProduct> collect1 = salesLedgerProducts.stream()
+                    .filter(j -> j.getId().equals(item.getSalesLedgerProductId()))
+                    .collect(Collectors.toList());
+            if(!CollectionUtils.isEmpty(collect1)){
+                SalesLedgerProduct salesLedgerProduct = collect1.get(0);
+                // 鏍规嵁浜у搧瑙勬牸 * 鎺掍骇鏁伴噺 鑾峰彇鏈鐢熶骇浜ч噺骞剁疮璁�
+                String[] split = salesLedgerProduct.getSpecificationModel().split("\\*");
+                BigDecimal productionNum = new BigDecimal(split[0])
+                        .multiply(new BigDecimal(split[1]).multiply(item.getSchedulingNum()));
+                totalNum.addAndGet(productionNum.intValue());
+            }
+        });
+        return new BigDecimal(totalNum.get());
+    }
+
     @Override
     public IPage<SalesLedgerSchedulingProcessDto> listPageProcess(Page page, SalesLedgerSchedulingProcessDto salesLedgerSchedulingDto) {
         IPage<SalesLedgerSchedulingProcessDto> list = salesLedgerSchedulingMapper.listPageProcess(page, salesLedgerSchedulingDto);
diff --git a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
index a135fa3..7628d95 100644
--- a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
+++ b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -59,6 +59,12 @@
     private String unit;
 
     /**
+     * 鐢熶骇鐐掓満
+     */
+    @Excel(name = "鐢熶骇鐐掓満")
+    private String speculativeTradingName;
+
+    /**
      * 鏁伴噺
      */
     @Excel(name = "鏁伴噺")
diff --git a/src/main/resources/mapper/production/SalesLedgerSchedulingMapper.xml b/src/main/resources/mapper/production/SalesLedgerSchedulingMapper.xml
index e7e882c..aacfbba 100644
--- a/src/main/resources/mapper/production/SalesLedgerSchedulingMapper.xml
+++ b/src/main/resources/mapper/production/SalesLedgerSchedulingMapper.xml
@@ -15,6 +15,7 @@
         T2.quantity,
         T2.product_category,
         T2.specification_model,
+        T2.speculative_trading_name,
         T2.unit
         FROM
         sales_ledger_product T2

--
Gitblit v1.9.3