From 51aeb12b0bd3030931b22c666b9c83e7ee51c800 Mon Sep 17 00:00:00 2001 From: sfd <sun.sunshine@163.com> Date: 星期五, 09 五月 2025 17:18:33 +0800 Subject: [PATCH] Merge branch 'dev' of http://192.168.50.149:8085/r/aps-backend into dev --- aps-modules/aps-core/src/main/resources/mapper/core/ApsPlatePlanMapper.xml | 5 - aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteLineMapper.xml | 14 ++++ aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireServiceImpl.java | 40 +++++++------ aps-modules/aps-job/src/main/resources/mapper/job/ApsWorkOrderJobMapper.xml | 4 aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomOrderDetailServiceImpl.java | 3 aps-modules/aps-core/src/main/java/com/aps/core/domain/ApsStandardProcessRouteLine.java | 12 +++ aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsStandardProcessRouteLineServiceImpl.java | 25 +------- aps-modules/aps-core/src/main/java/com/aps/core/mapper/ApsStandardProcessRouteLineMapper.java | 2 aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomStockDetailServiceImpl.java | 2 aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteHeaderMapper.xml | 1 aps-modules/aps-job/src/main/java/com/aps/job/service/impl/ApsWorkOrderJobServiceImpl.java | 3 aps-modules/aps-core/src/main/java/com/aps/core/controller/mainPlan/ApsStandardProcessRouteLineController.java | 14 ++++ 12 files changed, 74 insertions(+), 51 deletions(-) diff --git a/aps-modules/aps-core/src/main/java/com/aps/core/controller/mainPlan/ApsStandardProcessRouteLineController.java b/aps-modules/aps-core/src/main/java/com/aps/core/controller/mainPlan/ApsStandardProcessRouteLineController.java index cd8d9a7..2622075 100644 --- a/aps-modules/aps-core/src/main/java/com/aps/core/controller/mainPlan/ApsStandardProcessRouteLineController.java +++ b/aps-modules/aps-core/src/main/java/com/aps/core/controller/mainPlan/ApsStandardProcessRouteLineController.java @@ -8,11 +8,14 @@ import com.aps.common.log.enums.BusinessType; import com.aps.common.security.annotation.RequiresPermissions; import com.aps.core.domain.ApsStandardProcessRouteLine; +import com.aps.core.mapper.ApsStandardProcessRouteLineMapper; import com.aps.core.service.IApsStandardProcessRouteLineService; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.math.BigDecimal; import java.util.List; /** @@ -30,6 +33,8 @@ @Autowired private IApsStandardProcessRouteLineService apsStandardProcessRouteLineService; + @Resource + private ApsStandardProcessRouteLineMapper mapper; /** * 鏌ヨ鏍囧噯宸ヨ壓璺嚎Line鍒楄〃 */ @@ -97,4 +102,13 @@ { return toAjax(apsStandardProcessRouteLineService.deleteApsStandardProcessRouteLineByIds(ids)); } + + + + @PostMapping("/getStandardTime") + public AjaxResult getStandardTime(@RequestBody ApsStandardProcessRouteLine apsStandardProcessRouteLine) + { + BigDecimal standardTime = mapper.selectTotalStandTime(apsStandardProcessRouteLine.getRouteId()).getStandardTime(); + return toAjax(standardTime.intValue()); + } } diff --git a/aps-modules/aps-core/src/main/java/com/aps/core/domain/ApsStandardProcessRouteLine.java b/aps-modules/aps-core/src/main/java/com/aps/core/domain/ApsStandardProcessRouteLine.java index e75a25d..6f926f3 100644 --- a/aps-modules/aps-core/src/main/java/com/aps/core/domain/ApsStandardProcessRouteLine.java +++ b/aps-modules/aps-core/src/main/java/com/aps/core/domain/ApsStandardProcessRouteLine.java @@ -2,7 +2,7 @@ import com.aps.common.core.annotation.Excel; import com.aps.common.core.web.domain.BaseEntity; -import lombok.Builder; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -65,4 +65,14 @@ private Long delFlag; private BigDecimal routeTime; + + /** 宸ュ簭缂栫爜 */ + @Excel(name = "宸ュ簭缂栫爜") + @Schema(description = "宸ュ簭缂栫爜") + private String routeCode; + + /** 鏍囧噯宸ユ椂 */ + @Excel(name = "鏍囧噯宸ユ椂") + @Schema(description = "鏍囧噯宸ユ椂") + private BigDecimal standardTime; } diff --git a/aps-modules/aps-core/src/main/java/com/aps/core/mapper/ApsStandardProcessRouteLineMapper.java b/aps-modules/aps-core/src/main/java/com/aps/core/mapper/ApsStandardProcessRouteLineMapper.java index 6fb2a70..a06fdae 100644 --- a/aps-modules/aps-core/src/main/java/com/aps/core/mapper/ApsStandardProcessRouteLineMapper.java +++ b/aps-modules/aps-core/src/main/java/com/aps/core/mapper/ApsStandardProcessRouteLineMapper.java @@ -61,4 +61,6 @@ * @return 缁撴灉 */ public int deleteApsStandardProcessRouteLineByIds(Long[] ids); + + ApsStandardProcessRouteLine selectTotalStandTime(String routeHeaderId); } diff --git a/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomOrderDetailServiceImpl.java b/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomOrderDetailServiceImpl.java index bd6637b..0f54f59 100644 --- a/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomOrderDetailServiceImpl.java +++ b/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomOrderDetailServiceImpl.java @@ -14,6 +14,7 @@ import com.aps.core.mapper.ApsPlateStandardRequireBomOrderDetailMapper; import com.aps.core.domain.ApsPlateStandardRequireBomOrderDetail; import com.aps.core.service.IApsPlateStandardRequireBomOrderDetailService; +import org.springframework.transaction.annotation.Transactional; /** * ApsPlateStandardRequireBomOrderDetailService涓氬姟灞傚鐞� @@ -101,7 +102,7 @@ { return apsPlateStandardRequireBomOrderDetailMapper.deleteApsPlateStandardRequireBomOrderDetailById(id); } - + @Transactional @Override public void savePlastPlanAndBomOrderDetail(ApsPlateStandardRequire require, ApsPlatePlan platePlan, BigDecimal subtract, BigDecimal stock, BigDecimal netRequirement) { platePlan.setUnmatchedQuantity(subtract); diff --git a/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomStockDetailServiceImpl.java b/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomStockDetailServiceImpl.java index 3bb35b8..a3637e7 100644 --- a/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomStockDetailServiceImpl.java +++ b/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireBomStockDetailServiceImpl.java @@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; import com.aps.core.mapper.ApsPlateStandardRequireBomStockDetailMapper; import com.aps.core.service.IApsPlateStandardRequireBomStockDetailService; +import org.springframework.transaction.annotation.Transactional; /** * ApsPlateStandardRequireBomStockDetailService涓氬姟灞傚鐞� @@ -108,6 +109,7 @@ /** * 璁$畻鐗╂枡鍓╀綑搴撳瓨 骞朵繚瀛樼墿鏂欏墿浣欏簱瀛樻槑缁嗐�� * */ + @Transactional @Override public void saveStorageAndDetail(ApsMaterialStorageManagement itemStorage, ApsPlatePlan plan, String bomLineId,String itemCode, String batchNum, BigDecimal deductionAmount, BigDecimal afterStockAmount,Long requireId){ /*鏇存柊鐗╂枡鍓╀綑搴撳瓨*/ diff --git a/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireServiceImpl.java b/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireServiceImpl.java index e27bd1e..f49178f 100644 --- a/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireServiceImpl.java +++ b/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireServiceImpl.java @@ -166,7 +166,7 @@ /*瀹氫箟宸ュ巶涓哄崡閫� */ String plantCode="FORTUNA"; /*瀹氫箟涓诲崟绫诲瀷涓洪挘閲戜富鍗�*/ - String mainOrderType = "0"; + String mainOrderType = "main"; /*鐢熸垚鏂版壒娆″彿*/ String batchNum= requireBatchService.getNewBatchNumber(); /*鑾峰彇閽i噾涓诲崟淇℃伅*/ @@ -226,8 +226,6 @@ /*璁$畻闇�姹傛暟閲�*/ if (level == 0) { require.setBomUseAmount(BigDecimal.ONE); - require.setCompleteDate(plan.getPlanEndDay()); - require.setDemandDate(plan.getPlanEndDay()); } else { require.setBomUseAmount(itemNum.multiply(plan.getProductionQuantity())); } @@ -272,21 +270,27 @@ require.setProcessRouteId(routeId); require.setProcessRouteHours(String.valueOf(totalRouteTime)); - /*瀹屾垚鏃堕棿锛宭evel=0 鏃堕粯璁や负宸ュ崟鐨勮鍒掑畬鎴愭棩鏈�*/ - Date completeDate = plan.getPlanEndDay(); + /*棰勭暀澶╂暟*/ Long reservedDay = getReservedDays(); - if (level > 0) { + /*璁剧疆瀹屾垚鏃ユ湡*/ + if(level==0){ + /*瀹屾垚鏃堕棿锛宭evel=0 鏃堕粯璁や负宸ュ崟鐨勮鍒掑畬鎴愭棩鏈�*/ + require.setCompleteDate(plan.getPlanEndDay()); + require.setDemandDate(plan.getPlanEndDay()); + } else { /* 褰撳墠闇�姹傚畬鎴愭棩鏈熶负涓婇樁灞傞渶姹傜殑寮�濮嬫椂闂� - 棰勭暀澶╂暟(杞崲涓烘绉�)*/ long reservedMillisecond = reservedDay * 24 * millisecond; + Date completeDate = new Date(); completeDate.setTime(upLevelStartDate.getTime() - reservedMillisecond); + require.setCompleteDate(completeDate); + require.setDemandDate(completeDate); } - /*璁剧疆瀹屾垚鏃ユ湡*/ - require.setCompleteDate(completeDate); - require.setDemandDate(completeDate); + + /*璁剧疆寮�濮嬫椂闂�*/ Date startDay = new Date(); - startDay.setTime(completeDate.getTime() - totalRouteMillisecond); + startDay.setTime(require.getCompleteDate().getTime() - totalRouteMillisecond); require.setStartDate(startDay); /*璁$畻鏄惁鏈夐闄�*/ @@ -334,10 +338,10 @@ * 鑾峰彇閽i噾璁″垝 棰勭暀澶╂暟 * */ private Long getReservedDays(){ - Long days=0L; - List<SysDictData> dictDataList = DictUtils.getDictCache("aps_is_suspended"); - if (dictDataList != null) { - Long.getLong(dictDataList.get(0).getDictValue()); + long days=0L; + List<SysDictData> dictDataList = DictUtils.getDictCache("plate_plan_param"); + if (dictDataList != null && !dictDataList.isEmpty()) { + days = Long.parseLong(dictDataList.get(0).getDictValue()); } return days; } @@ -361,7 +365,7 @@ bomOrderDetailService.savePlastPlanAndBomOrderDetail(require, platePlan, subtract, stock, netRequirement); netRequirement = BigDecimal.ZERO; require.setMatchState("宸插尮閰�"); - require.setUnmatchedDemandAmount(netRequirement); + require.setUnmatchedDemandAmount(BigDecimal.ZERO); /*鍑�闇�姹傚凡缁忚婊¤冻锛屼笉闇�瑕佺户缁尮閰�*/ } else if (netRequirement.compareTo(stock) == 0) { @@ -371,7 +375,7 @@ bomOrderDetailService.savePlastPlanAndBomOrderDetail(require, platePlan, subtract, stock, netRequirement); netRequirement = BigDecimal.ZERO; require.setMatchState("宸插尮閰�"); - require.setUnmatchedDemandAmount(netRequirement); + require.setUnmatchedDemandAmount(BigDecimal.ZERO); /*鍑�闇�姹傚凡缁忚婊¤冻锛屼笉闇�瑕佺户缁尮閰�*/ } if (netRequirement.compareTo(stock) > 0) { @@ -385,12 +389,10 @@ platePlan = apsPlatePlanMapper.selectUnMatchPlateSubPlan(require.getOrgCode(), require.getBomLineCode()); /*鍓╀綑鍑�闇�姹�*/ netRequirement = rest; - require.setUnmatchedDemandAmount(netRequirement); + require.setUnmatchedDemandAmount(rest); } } } - require.setUnmatchedDemandAmount(require.getNetRequirement()); - } diff --git a/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsStandardProcessRouteLineServiceImpl.java b/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsStandardProcessRouteLineServiceImpl.java index dcb1503..d0d3b21 100644 --- a/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsStandardProcessRouteLineServiceImpl.java +++ b/aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsStandardProcessRouteLineServiceImpl.java @@ -4,6 +4,7 @@ import java.util.Hashtable; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import cn.hutool.core.util.IdUtil; import com.aps.common.core.utils.DateUtils; @@ -115,8 +116,6 @@ */ @Override public ApsStandardProcessRouteLine getRouteLineTotalTime(ApsPlateStandardRequire require) { - // 瀹氫箟鐙崰鐢熶骇妯″紡甯搁噺 - String productivityModel_monopolize = "鐙崰"; // 鍒濆鍖栨�诲伐鏃朵负0 BigDecimal totalRouteTime = BigDecimal.ZERO; //宸ュ巶 @@ -127,7 +126,6 @@ ApsStandardProcessRouteLine ret=new ApsStandardProcessRouteLine(); ret.setRouteId(String.valueOf(routId)); ret.setRouteTime(BigDecimal.ZERO); - // 鏌ヨ鏍囧噯宸ヨ壓璺嚎澶撮儴淇℃伅 Optional<ApsStandardProcessRouteHeader> firstProcessRoute = standardProcessRouteHeaderMapper.queryStandardProcessRouteHeaderByPlantAndItemCode(plant, itemNumber).stream().findFirst(); if (firstProcessRoute.isPresent()) { @@ -135,26 +133,9 @@ // 鏋勫缓宸ヨ壓璺嚎琛屽弬鏁板璞� ApsStandardProcessRouteLine routeLineParam =new ApsStandardProcessRouteLine(); routeLineParam.setRouteId(routeHeader.getRouteId()); - // 鏌ヨ鏍囧噯宸ヨ壓璺嚎琛屼俊鎭� - List<ApsStandardProcessRouteLine> apsStandardProcessRouteLines = apsStandardProcessRouteLineMapper.selectApsStandardProcessRouteLineList(routeLineParam); - /*宸ヨ壓璺嚎Line 鎬诲伐鏃�*/ - - if(apsStandardProcessRouteLines.isEmpty()){ - saveRequireError(require,"宸ュ簭涓嶅瓨鍦�"); - }else { - // 閬嶅巻姣忎釜宸ヨ壓璺嚎琛� - apsStandardProcessRouteLines.forEach(line -> { - // 榛樿灏嗚璁′骇鑳借缃负璺嚎鏃堕棿 - line.setRouteTime(line.getDesignCapacity()); - // 濡傛灉鐢熶骇妯″紡涓虹嫭鍗狅紝鍒欒矾绾挎椂闂翠负璁捐浜ц兘涔樹互鍑�闇�姹傞噺 - if (line.getProductivityModel().equals(productivityModel_monopolize)) { - line.setRouteTime(line.getDesignCapacity().multiply(require.getNetRequirement())); - } - // 绱姞璺嚎鏃堕棿鍒版�诲伐鏃朵腑 - totalRouteTime.add(line.getRouteTime()); - }); - } + BigDecimal standardTime = apsStandardProcessRouteLineMapper.selectTotalStandTime(routeHeader.getRouteId()).getStandardTime(); + totalRouteTime =standardTime.multiply(require.getNetRequirement()); ret.setRouteTime(totalRouteTime); ret.setRouteId(routeHeader.getRouteId()); }else { diff --git a/aps-modules/aps-core/src/main/resources/mapper/core/ApsPlatePlanMapper.xml b/aps-modules/aps-core/src/main/resources/mapper/core/ApsPlatePlanMapper.xml index 7d407f4..b53581e 100644 --- a/aps-modules/aps-core/src/main/resources/mapper/core/ApsPlatePlanMapper.xml +++ b/aps-modules/aps-core/src/main/resources/mapper/core/ApsPlatePlanMapper.xml @@ -271,8 +271,7 @@ <select id="selectPlatePlanByPlantMajor" parameterType="ApsPlatePlan" resultMap="ApsPlatePlanResult"> select id,document_number,main_part_number,item_number,plant,professional_affiliation,production_quantity,require_id, - unmatched_quantity,version, production_base, - (case when custom_time is null then plan_end_day else custom_time end ) as plan_end_day + unmatched_quantity,version, production_base,plan_end_day from aps_plate_plan <where> <if test="plant != null "> and plant = #{plant}</if> @@ -286,7 +285,7 @@ select id,document_number,main_part_number,item_number,plant,professional_affiliation,production_quantity, unmatched_quantity,version from aps_plate_plan - where del_flag='0' and professional_affiliation !='0' and unmatched_quantity > 0 + where del_flag='0' and professional_affiliation ='sub' and unmatched_quantity > 0 <if test="plant != null and plant !='' "> and plant = #{plant}</if> <if test="itemNumber != null and itemNumber !='' "> and item_number = #{itemNumber}</if> order by document_number asc,id asc diff --git a/aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteHeaderMapper.xml b/aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteHeaderMapper.xml index 7b152eb..0416d52 100644 --- a/aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteHeaderMapper.xml +++ b/aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteHeaderMapper.xml @@ -39,6 +39,7 @@ <if test="orgCode != null and orgCode != ''"> and org_code = #{orgCode}</if> and del_flag = '0' </where> + ORDER BY version desc </select> <select id="selectApsStandardProcessRouteHeaderById" parameterType="Long" resultMap="ApsStandardProcessRouteHeaderResult"> diff --git a/aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteLineMapper.xml b/aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteLineMapper.xml index 9f94cbf..1965e12 100644 --- a/aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteLineMapper.xml +++ b/aps-modules/aps-core/src/main/resources/mapper/core/ApsStandardProcessRouteLineMapper.xml @@ -20,18 +20,20 @@ <result property="createBy" column="create_by" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> + <result property="routeCode" column="route_code" /> + <result property="standardTime" column="standard_time" /> </resultMap> <sql id="selectApsStandardProcessRouteLineVo"> select id, route_id, route_num, route_name, start_date, end_date, create_time, org_code, shop_code, productivity_model, design_capacity, del_flag, create_by, update_by, - update_time + update_time, route_code, standard_time from aps_standard_process_route_line </sql> <select id="selectApsStandardProcessRouteLineList" parameterType="ApsStandardProcessRouteLine" resultMap="ApsStandardProcessRouteLineResult"> <include refid="selectApsStandardProcessRouteLineVo"/> - <where> + <where> <if test="routeId != null and routeId != ''"> and route_id = #{routeId}</if> <if test="routeNum != null and routeNum != ''"> and route_num = #{routeNum}</if> <if test="routeName != null and routeName != ''"> and route_name = #{routeName}</if> @@ -43,6 +45,7 @@ <if test="designCapacity != null and designCapacity != ''"> and design_capacity = #{designCapacity}</if> and del_flag = '0' </where> + </select> <select id="selectApsStandardProcessRouteLineById" parameterType="Long" resultMap="ApsStandardProcessRouteLineResult"> @@ -119,4 +122,11 @@ #{id} </foreach> </delete> + + <select id="selectTotalStandTime" parameterType="String" resultMap="ApsStandardProcessRouteLineResult"> + select sum(standard_time) as standard_time + from aps_standard_process_route_line + where route_id = #{routeId} + ; + </select> </mapper> \ No newline at end of file diff --git a/aps-modules/aps-job/src/main/java/com/aps/job/service/impl/ApsWorkOrderJobServiceImpl.java b/aps-modules/aps-job/src/main/java/com/aps/job/service/impl/ApsWorkOrderJobServiceImpl.java index fc2078b..c45b643 100644 --- a/aps-modules/aps-job/src/main/java/com/aps/job/service/impl/ApsWorkOrderJobServiceImpl.java +++ b/aps-modules/aps-job/src/main/java/com/aps/job/service/impl/ApsWorkOrderJobServiceImpl.java @@ -159,7 +159,7 @@ param.setDocState(Arrays.asList(0,1,2,4)); param.setBeginDate(yesterdayMidnight.format(formatter)); param.setEndDate(today.format(formatter)); - param.setPageSize(100); + param.setPageSize(500); while (continueFlag){ param.setPageIndex(currentPage); continueFlag= batchSaveByPager(param); @@ -303,6 +303,7 @@ order.setProcessStatus("0"); order.setOpStatus(jsonObject.getString("OpStatus")); order.setNextOpName(jsonObject.getString("NextOpName")); + order.setLowOrderCode(jsonObject.getString("LowLevelCode")); jobs.add(order); orderIds.add(order.getOrderId()); } catch (Exception e) { diff --git a/aps-modules/aps-job/src/main/resources/mapper/job/ApsWorkOrderJobMapper.xml b/aps-modules/aps-job/src/main/resources/mapper/job/ApsWorkOrderJobMapper.xml index 6edc249..2da09bb 100644 --- a/aps-modules/aps-job/src/main/resources/mapper/job/ApsWorkOrderJobMapper.xml +++ b/aps-modules/aps-job/src/main/resources/mapper/job/ApsWorkOrderJobMapper.xml @@ -417,8 +417,8 @@ op_num,work_center,dept, start_date,complete_date,next_dept, is_hold_release,is_out_source,org_code, - order_id,now(),'0',org_code,doc_status,std_op,op_status,next_op_name, - case when low_order_code='0' then 'main' else 'sub' end as professional_affiliation, + cast(order_id as bigint) as id,now(),'0',org_code,doc_status,std_op,op_status,next_op_name, + (case when low_order_code='0' then 'main' else 'sub' end ) as professional_affiliation, order_create_time from aps_work_order_job where ( doc_status in (0,1,2,4) and is_hold_release='0' -- Gitblit v1.9.3