根据订单获取可退货项流程分析
退货的时候,调用 services_return.xml 中的获取可进行退货的退货项  getReturnableItems  ,该服务调用了Java类 org.ofbiz.order.order.OrderReturnServices 中的getReturnableItems方法。
通过获取到的orderId 获得相对应的订单,通过查询条件,(orderId = 'DEMO1002' AND orderItemStatusId IN ('ITEM_APPROVED', 'ITEM_COMPLETED'))
去执行 OrderItemQuantityReportGroupByItem 视图查询,获取 根据item分组得到的数据列表 ,
根据订单的类型判断订单是否为销售订单(SALES_ORDER),
根据上面分组得到的数据列表进行循环调用 getReturnableQuantity service服务,该服务调用的同样是上述java类中的getReturnableQuantity方法,
根据orderItem中的productId 获取对应的Product实体对象,根据该商品的returned属性,去判断该商品是否支持退货操作。
在根据该商品的supportDiscontinuationDate 的支持终止日期与当前时间做比较,如果小于当前时间,则不能进行退货操作。
定义一个orderQty变量,如果可以进行退货操作,获取orderItem的数量并进行赋值,如果orderItem中的cancelQuantity数目存在的话,将cancelQuantity与orderQty相减获取订单的数目,赋值给orderQty变量,
获取orderItem的statusId状态,如果状态存在于ITEM_APPROVED 或者 ITEM_COMPLETED中,进行下面的循环。
根据OrderItem获取对应的退货项列表,如果退货项为空的话,可退货数目则为上面定义的orderQty的值,
如果退货项列表不为空的话,定义一个returnedQty变量,对列表进行循环,如果退货项的状态不为RETURN_CANCELLED,就对returnedQty 进行 增加的操作,最终将订单的orderQty数目与 returnedQty 数目相减,获取该orderitem可归还的数目。
 
 
 
生成退货单流程分析
因为我个人是打算用的ofbiz里面的service服务的,因此,要直接使用这个服务的时候,要求界面上的所要提交的参数值要保证跟ofbiz原生的页面相差不多,因此,直接对使用ofbiz原生的页面进行样式修改。
调用上面的获取可退货项的服务之后,获取了页面之后,然后进行提交,提交的target为createReturnAndItemOrAdjustment这个服务(control里面的调用事件type为service-multi),这个服务是调用simplemethod方法,method定义的文件为component://order/script/org/ofbiz/order/order/OrderReturnServices.xml,调用的方法为createReturnAndItemOrAdjustment,
先判断参数里面是否包含returnId,如果returnId为空,则创建退货单,然后根据返回回来的returnId,去调用createReturnItemOrAdjustment这个服务,这个服务的实现方法是使用java的方式,java类为org.ofbiz.order.order.OrderReturnServices,调用的方法为createReturnItemOrAdjustment,判断orderItemSeqId是否存在,如果存在,则调用createReturnItem,如果不存在,则调用createReturnAdjustment服务。
 
createReturnItem 服务是使用simplemethod的 方式,method的定义文件为component://order/script/org/ofbiz/order/order/OrderReturnServices.xml,调用方法为createReturnItem,这个服务里面有很多判断,例如是否有权限,是否有returntypeId,是否有归还数目等等,具体的要到对应的文件里面去看具体实现方法。
 
受理退货单
首先调用updateReturnHeader服务,服务定义在services_return.xml文件中,服务的实现方法为simple-method,定义文件为component://order/script/org/ofbiz/order/order/OrderReturnServices.xml,调用的方法为updateReturnHeader
在该服务中,没有明显的其他操作,但是很明显的在执行updateReturnHeader这个服务的时候,在后台能看到执行了好多其他的方法,说明在secas.xml中定义了该服务执行时会触发别的服务的执行。该文件一般存在于/emt/applications/order/servicedef/secas.xml   即跟服务文件同目录下,然后然后去看对应的服务在某些condition条件的满足下,会触发哪些别的服务。
 <eca service="updateReturnHeader" event="return">
<condition field-name="statusId" operator="equals" value="RETURN_ACCEPTED"/>
<!-- The quickReceiveReturn service checks this, and some status update calls may not pass it in, so don't
check it here or the option may be ignored.
<condition field-name="needsInventoryReceive" operator="equals" value="Y"/> -->
<action service="quickReceiveReturn" mode="sync"/>
</eca>
<eca service="updateReturnHeader" event="commit">
<condition field-name="statusId" operator="equals" value="RETURN_ACCEPTED"/>
<condition field-name="oldStatusId" operator="not-equals" value="RETURN_ACCEPTED"/>
<action service="processWaitReplacementReservedReturn" mode="sync"/>
<action service="processReplaceImmediatelyReturn" mode="sync"/>
<action service="createShipmentAndItemsForReturn" mode="sync"/>
<action service="processCrossShipReplacementReturn" mode="sync"/>
<action service="createTrackingCodeOrderReturns" mode="sync" run-as-user="system"/>
<action service="sendReturnAcceptNotification" mode="async" persist="true"/>
<action service="processRefundImmediatelyReturn" mode="sync"/>
<action service="createReturnStatus" mode="sync"/>
</eca>

首先当触发event事件并且statusId状态为RETURN_ACCEPTED的时候,就会调用quickReceiveReturn服务,下面为该服务的逻辑判断,如果嫌长可以快速掠过。

 <simple-method method-name="quickReceiveReturn" short-description="Quick Receive Entire Return">
<entity-one entity-name="ReturnHeader" value-field="returnHeader">
<field-map field-name="returnId" from-field="parameters.returnId"/>
</entity-one> <if-compare field="returnHeader.needsInventoryReceive" operator="equals" value="Y">
<!-- before receiving inventory, check to see if there is inventory information in this database -->
<entity-count entity-name="InventoryItem" count-field="iiCount">
<condition-expr field-name="facilityId" operator="equals" from-field="returnHeader.destinationFacilityId"/>
</entity-count> <if-compare field="iiCount" operator="greater" value="0" type="Integer">
<!-- create a return shipment for this return -->
<set field="shipmentCtx.returnId" from-field="parameters.returnId"/>
<call-service service-name="createShipmentForReturn" in-map-name="shipmentCtx">
<result-to-field result-name="shipmentId"/>
</call-service>
<log level="info" message="Created new shipment ${shipmentId}"/> <entity-condition entity-name="ReturnItem" list="returnItems">
<condition-expr field-name="returnId" operator="equals" from-field="returnHeader.returnId"/>
</entity-condition> <!-- if no inventory item type specified, get default from facility -->
<if-empty field="parameters.inventoryItemTypeId">
<get-related-one value-field="returnHeader" relation-name="Facility" to-value-field="facility"/>
<set field="parameters.inventoryItemTypeId" from-field="facility.defaultInventoryItemTypeId" default-value="NON_SERIAL_INV_ITEM"/>
</if-empty> <now-timestamp field="nowTimestamp"/> <entity-count entity-name="ReturnItem" count-field="returnItemCount">
<condition-expr field-name="returnId" operator="equals" from-field="returnHeader.returnId"/>
</entity-count>
<set field="nonProductItems" type="Long" value="0"/> <iterate entry="returnItem" list="returnItems">
<!-- record this return item on the return shipment as well. not sure if this is actually necessary... -->
<clear-field field="shipItemCtx"/>
<set from-field="shipmentId" field="shipItemCtx.shipmentId"/>
<set from-field="returnItem.productId" field="shipItemCtx.productId"/>
<set from-field="returnItem.returnQuantity" field="shipItemCtx.quantity"/>
<log level="info" message="calling create shipment item with ${shipItemCtx}"/>
<call-service service-name="createShipmentItem" in-map-name="shipItemCtx">
<result-to-field result-name="shipmentItemSeqId"/>
</call-service>
</iterate>
<iterate entry="returnItem" list="returnItems">
<clear-field field="receiveCtx"/> <if-empty field="returnItem.expectedItemStatus">
<set value="INV_RETURNED" field="returnItem.expectedItemStatus" type="String"/>
</if-empty>
<get-related-one value-field="returnItem" relation-name="OrderItem" to-value-field="orderItem"/>
<if-not-empty field="orderItem.productId">
<set field="costCtx.returnItemSeqId" from-field="returnItem.returnItemSeqId"/>
<set field="costCtx.returnId" from-field="returnItem.returnId"/>
<call-service service-name="getReturnItemInitialCost" in-map-name="costCtx">
<result-to-field result-name="initialItemCost" field="receiveCtx.unitCost"/>
</call-service>
<!--check if the items already have SERIALIZED inventory. If so, it still puts them back as SERIALIZED with status "Accepted."-->
<entity-count entity-name="InventoryItem" count-field="serializedItemCount">
<condition-list combine="and">
<condition-expr field-name="productId" operator="equals" from-field="returnItem.productId"/>
<condition-expr field-name="facilityId" operator="equals" from-field="returnHeader.destinationFacilityId"/>
<condition-expr field-name="inventoryItemTypeId" operator="equals" value="SERIALIZED_INV_ITEM"/>
</condition-list>
</entity-count>
<set field="setNonSerial" value="false"/>
<if-compare field="parameters.inventoryItemTypeId" value="NON_SERIAL_INV_ITEM" operator="equals">
<if-compare field="serializedItemCount" value="0" operator="equals">
<set field="parameters.inventoryItemTypeId" value="NON_SERIAL_INV_ITEM"/>
<set field="setNonSerial" value="true"/>
</if-compare>
</if-compare>
<if-compare field="setNonSerial" value="false" operator="equals">
<set field="parameters.inventoryItemTypeId" value="SERIALIZED_INV_ITEM"/>
<set field="returnItem.returnQuantity" value="1" type="BigDecimal"/>
</if-compare> <set from-field="parameters.inventoryItemTypeId" field="receiveCtx.inventoryItemTypeId"/>
<set from-field="returnItem.expectedItemStatus" field="receiveCtx.statusId"/>
<set from-field="returnItem.productId" field="receiveCtx.productId"/>
<set from-field="returnItem.returnItemSeqId" field="receiveCtx.returnItemSeqId"/>
<set from-field="returnItem.returnId" field="receiveCtx.returnId"/>
<set from-field="returnItem.returnQuantity" field="receiveCtx.quantityAccepted"/>
<set from-field="returnHeader.destinationFacilityId" field="receiveCtx.facilityId"/>
<!-- important: associate ShipmentReceipt with return shipment created -->
<set field="receiveCtx.shipmentId" from-field="shipmentId"/> <set field="receiveCtx.comments" value="Returned Item RA# ${returnItem.returnId}"/>
<set field="receiveCtx.datetimeReceived" from-field="nowTimestamp"/>
<set field="receiveCtx.quantityRejected" value="0" type="BigDecimal"/> <call-service service-name="receiveInventoryProduct" in-map-name="receiveCtx"/>
<else>
<calculate field="nonProductItems" type="Long">
<calcop operator="add">
<number value="1"/>
</calcop>
</calculate>
</else>
</if-not-empty>
</iterate> <!-- now that the receive is done; set the need flag to N -->
<refresh-value value-field="returnHeader"/>
<set field="returnHeader.needsInventoryReceive" value="N"/>
<store-value value-field="returnHeader"/> <!-- always check/update the ReturnHeader status, even though it might have been from the receiving above, just make sure -->
<if-compare field="returnHeader.statusId" operator="not-equals" value="RETURN_RECEIVED">
<set field="retStCtx.returnId" from-field="returnHeader.returnId"/>
<set field="retStCtx.statusId" value="RETURN_RECEIVED"/>
<call-service service-name="updateReturnHeader" in-map-name="retStCtx"/>
</if-compare>
<else>
<log level="info" message="Not receiving inventory for returnId ${returnHeader.returnId}, no inventory information available."/>
</else>
</if-compare>
</if-compare>
</simple-method>

大概分析下该simple-method方法,判断returnHeader退货头的needsInventoryReceive字段(需要仓库接收 ),如果是的话,判断退货头的DESTINATION_FACILITY_ID是否等于facilityId,如果等于,就获取库存项的数目,如果库存量大于0,则调用createShipmentForReturn(创建针对退货的装运头)的服务,生成shipmentId,然后判断参数parameters.inventoryItemTypeId是否为空,如果为空,就给默认值NON_SERIAL_INV_ITEM,获取退货项的数目,循环退货项的列表,调用createShipmentItem(装运项)服务,接着继续根据退货项列表循环调用receiveInventoryProduct(创建新的库存项目接收库存(S))服务。

然后还会调好多的别的服务,我就实在没有心思一一仔细阅读了,最后还需要调用这个createReturnStatus服务,这个服务就跟流程日志一样,不管是创建还是针对该对象进行的任何修改操作,都会新增一条这样的状态,用于跟踪退货单的流程。

ofbiz进击 。 ofbiz 退货流程(包含获取可退货项流程分析 以及 取消退货项的过程分析)的更多相关文章

  1. activiti自定义流程之整合(五):启动流程时获取自定义表单

    流程定义部署之后,自然就是流程定义列表了,但和前一节一样的是,这里也是和之前单独的activiti没什么区别,因此也不多说.我们先看看列表页面以及对应的代码,然后在一步步说明点击启动按钮时如何调用自定 ...

  2. Net Core 使用外部登陆提供程序登陆的流程,以及身份认证的流程

    在Asp.Net Core 中使用外部登陆(google.微博...)   原文出自Rui Figueiredo的博文<External Login Providers in ASP.NET C ...

  3. Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程

    本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...

  4. activiti 一个流程的运转步骤 以请假流程为例

    ---为了加深对activiti的理解记忆,对自己做的一个流程进行自述.加强记忆 请假实例 一.设计请假的流程图以及流程文件,完善对应数据项,比如用户信息,请假单信息 --请假单 --流程图 --流程 ...

  5. Activiti第二篇【管理流程定义、执行任务和流程实例、流程变量】

    上篇Activiti只是一个快速入门案例,这篇就讲定义.部署.查看任务等等的一些细节[涉及到的数据库表.对象等等]- 管理流程定义 管理流程定义主要涉及到以下的4张表: -- 流程部署相关的表 SEL ...

  6. 以太网驱动的流程浅析(四)-以太网驱动probe流程【原创】

    以太网驱动的流程浅析(四)-以太网驱动probe流程 Author:张昺华 Email:920052390@qq.com Time:2019年3月23日星期六 此文也在我的个人公众号以及<Lin ...

  7. 034 01 Android 零基础入门 01 Java基础语法 04 Java流程控制之选择结构 01 流程控制概述

    034 01 Android 零基础入门 01 Java基础语法 04 Java流程控制之选择结构 01 流程控制概述 本文知识点:Java中的流程控制相关概念的认识 三大流程控制语句结构的简介 顺序 ...

  8. .NET 开源工作流: Slickflow流程引擎高级开发(十) -- BpmnJS流程设计器集成

    前言: 在Slickflow产品开发过程中,前端流程设计器经历了几个不同的版本(jsPlumb, mxGraph等),目的是为了在设计流程时的用户体验更加良好,得到客户的好评和认可.BpmnJS流程设 ...

  9. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

随机推荐

  1. php读取memcahed java session

    PHP 共享 JAVA 保存的session信息 情景: 1:现在有两个系统,一个是Java做的系统,一个是PHP的系统,现在要把两个系统弄成一个单点登录. 2:两个系统两个库,两个库的表结构完全不同 ...

  2. svn截图

        一.合并一个范围的版本 此类型应用最为广泛,主要是把分支中的修改合并到主干上来.在主干上点击右键选择合并,然后选择合并类型:合并一个范围的版本.合并的源URL填写的是要合并的分支的URL,待合 ...

  3. 处理PHP字符串的10个简单方法;mysql出现乱码:character_set_server=utf8

    PHP处理字符串的能力非常强大,方法也是多种多样,但有的时候你需要选择一种最简单且理想的解决方法.文章列举了10个PHP中常见的字符串处理案例,并提供了相对应的最理想的处理方法. 1.确定一个字符串的 ...

  4. Windows下git使用代理服务器的设置方法

    在我朝独有的无敌GFW关照下(当然,也有可能IP被网站封了),要下载网络上开源的软件是非常困难的一件事情,在这种情况下,使用VPN或者代理服务器就非常有必要了.对于单个应用FQ来说,个人比较喜欢用FQ ...

  5. Cocos2d-JS切换场景与切换特效

    var HelloWorldLayer = cc.Layer.extend({ sprite:null, ctor:function () { //////////////////////////// ...

  6. 几个简单的html+css+js题目

    1.页面中有一图片,请在下划线处添加代码能够实现隐藏该图片的功能 <img id="pic" src="door.jpg" width="200 ...

  7. 集合类(Objective-C & Swift)

    内容提要: 本文前两部分讲了Cocoa的集合类和Swift的集合类,其中Cocoa提供的集合类包括NSArray.NSMutableArray.NSDictionary.NSMutableDictio ...

  8. 转:自定义ASP.NET MVC Html辅助方法

    在ASP.NET MVC中,Html辅助方法给我们程序员带来很多方便,其重要性也就不言自明.有时候,我们不想重复地写一些HTML代码,或者MS没有提供我们想要的那个HTML标签的Html辅助方法,那么 ...

  9. LightOj1074 - Extended Traffic(SPFA最短路)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1074 题意:有n个城市,每个城市有一个拥堵值a[i],m条单向路u到v,从u到v所需时 ...

  10. PMP--可能会涉及到的计算题

    一.进度管理里的历时三点估算历时的三点估算可能会出现在进度管理的计算题里.以下公式,大家要记住:说一下历时的三点估算中的几个值:1.最有可能的历时估算:Tm2.最乐观的历时估算: To3.最悲观的历时 ...