1.计数单开单
1.1 数据表设计
怎么进行数据库的编写的,设计的好处。
1.1.1 数据库设计:计数单主表、明细表、日志表
1.1.1.1 count
表包含以下字段:
rec_id
:主键,自增长的整数类型,采购申请单的唯一标识。purchase_apply_no
:计数单编号,长度为20的字符串类型。status
:表示计数单的状态,是一个小整数类型,默认值为10。具体取值说明如下:- 5:已取消
- 10:编辑中
- 20:已提交
- 25:部分引用
- 30:已引用
creator_id
:创建者的唯一标识,整数类型。warehouse_id
:仓库的唯一标识,小整数类型,默认值为0。remark
:备注信息,长度为255的字符串类型,默认值为空字符串。modified
:最后修改时间,时间戳类型,设置为当前时间,每次更新时自动更新。created
:创建时间,时间戳类型,设置为当前时间。
1.1.1.2 count_detail
表包含以下字段:
rec_id
:主键,自增长的整数类型,采购申请明细的唯一标识。apply_id
:关联的采购申请单的唯一标识,整数类型。spec_id
:规格的唯一标识,整数类型。real_num
:数量,decimal类型,精度为19位,小数点后4位,不能为空。remark
:备注信息,长度为255的字符串类型,默认值为空字符串。version_id
:版本号,整数类型,默认值为0。modified
:最后修改时间,时间戳类型,设置为当前时间,每次更新时自动更新。created
:创建时间,时间戳类型,设置为当前时间。- 建立索引(created)
- 建立索引(
apply_id
)
1.1.1.3 count_log
表包含以下字段:
rec_id
:主键,自增长的长整数类型,采购申请日志的唯一标识。apply_id
:关联的采购申请单的唯一标识,整数类型。operator_id
:操作者的唯一标识,整数类型。remark
:备注信息,长度为255的字符串类型,默认值为空字符串。created
:创建时间,时间戳类型,设置为当前时间。- 建立索引(created)
- 建立索引(
apply_id
)
1.1.1.4
为什么要这样进行设计数据库表?
建立了count表后,仅记录计数单的基本信息是不够的,因为计数单涉及到多个明细,每个明细还有数量等信息,需要单独建立一个明细表count_detail来记录每个计数单的明细信息,这样可以带来以下好处:
-
数据结构更清晰:将计数单的基本信息和明细信息分别存储在两张表中,可以使数据结构更加清晰,易于理解和维护。
-
方便查询和统计:将计数单的明细信息单独存储在count_detail表中,可以方便地进行查询和统计,例如可以按照采购申请单、规格等字段进行筛选和排序,从而更加方便地了解计数单的具体情况。
-
易于扩展:如果需要添加新的字段或者修改字段类型,单独维护明细表count_detail就会更加方便,不会影响到计数单基本信息表count。
-
降低数据冗余:将计数单的明细信息单独存储在count_detail表中,避免了重复存储计数单的基本信息,可以降低数据冗余,提高数据库的性能和存储效率。
综上所述,建立count_detail表可以使数据结构更清晰,方便查询和统计,易于扩展,同时也可以降低数据冗余,提高数据库的性能和存储效率。
-
数据结构清晰:通过将采购申请相关的数据拆分到不同的表中,可以使数据结构更加清晰明确。每个表都专注于存储特定的信息,例如
count
表存储采购申请单的基本信息,count_detail
表存储采购申请明细的信息,count_log
表存储采购申请的操作日志。这种拆分可以提高数据的可读性和可维护性。 -
数据一致性:通过使用关联字段(如
apply_id
)将不同表中的数据关联起来,可以确保数据的一致性。例如,count_detail
表中的每条记录都与count
表中的某个采购申请单关联,这样可以避免出现孤立的数据或数据冗余。同时,通过在count
表中使用版本号字段(version_id
),可以实现乐观锁机制,确保数据的更新是基于最新的版本,避免并发操作导致的数据冲突。 -
查询性能优化:通过合理地设计表的索引,可以提高查询性能。例如,在
count
表中可以为常用查询条件(如status
、creator_id
等)创建索引,以加快查询速度。此外,通过合理使用关联查询(JOIN)等操作,可以在多个表之间进行高效的数据检索和关联操作。 -
数据统计与分析:由于数据被拆分到不同的表中,可以更方便地进行数据统计和分析。例如,可以通过对
count_detail
表中的数量字段进行汇总,得到某个采购申请单的总数量。同时,可以根据pcount_log
表中的操作记录,进行操作日志的查询和分析,了解采购申请的操作历史。 -
扩展性和灵活性:通过将采购申请相关的数据拆分到不同的表中,可以更容易地进行系统扩展和功能调整。例如,如果需要增加新的采购申请属性或者关联其他表,只需修改相应的表结构,而不会对整个系统产生较大的影响。这种表的设计使系统更加灵活,方便适应未来的需求变化。
总的来说,根据上述三个表建立计数开单的开发方案,从表的角度来看,可以提供清晰的数据结构、数据一致性、查询性能优化、数据统计与分析、扩展性和灵活性等好处。这些好处有助于提高系统的可维护性、性能和可扩展性,为用户提供更好的使用体验和数据管理能力。
1.1.1.5 查数据库的Java拼接过程:
查询方法的一般格式:(查询有很多种,这里以一般页面载入的时候使用的分页查询为例)
public Response query(Session session, Map<String, String> params, Pager pager)
如果使用分页查询,其中参数 Session session, Pager pager是固定的,中间的参数是你传入的参数,个数自己控制
流程:
1.构造where,
2.构造table
3.添加查询字段
1.2 页面设计
对前端协调沟通后的页面设计进行了数据库表的建立。(答出数据库表的字段对应的前端的位置)
页面能够选择单品,选择货品页面可以使用已有页面
页面要求有对单据进行保存,提交,审核、驳回审核、返回编辑操作,
能够进行针对单据、货品、单品的常用搜索
单据要求至少有编辑中、待审核、已审核状态
单据操作必须有日志,对应的状态校验,数量和状态检查等 需对可能产生的异常操作进行校验/提示/处理
1.3 页面逻辑 C#(暂时不考虑)
对于进行Java后端进行的数据库的数据查询,前端如何进行处理,进行业务方面的问题的协调。
<btn #btn_add_spec .icon_add_goods>添加单品</btn>
<btn #btn_del_spec .icon_delete>删除单品</btn>
#purchase_apply_detail:进行界面内容的展示
[Click("#btn_del_spec")]删除单品
[DblClickTR("#purchase_apply_detail")]
1.4 编写独立的计数单开单页面,管理页面能够选择单品,能够手工填写单品数量
如何用代码实现的:
1.4.1 Java:添加单品功能
purchase.PurchaseApply.queryOneTest
查询的Java代码:放入到:#purchase_apply
@Export
@BindAttributes("rec_id,status,version_id")
@ServerTransforms("warehouse_name(warehouse_id+warehouse_name),employee_name(creator_id+creator_name)")
public Response queryOneTest(Session session, int applyID) throws SQLException
{
return session.db(false)
.query("SELECT pa.rec_id," +
"pa.purchase_count_no," +
"pa.`status`," +
"pa.warehouse_id,"+
" SUM(pad.real_num) AS real_num," +//
"date(pa.expected_time) AS expected_time,"+
" pa.remark," +
"pa.creator_id," +
"pa.version_id," +
"pa.modified," +
"pa.created " +
// " FROM purchase_apply pa"
"FROM count pa"
// + " LEFT JOIN purchase_apply_detail pad ON pad.apply_id = pa.rec_id"
+ " LEFT JOIN zlw_count_detail pad ON pad.apply_id = pa.rec_id"
+ " WHERE pa.rec_id=? " +
"GROUP BY pa.rec_id", applyID);
}
purchase.PurchaseApply.getDetailToUpdateTest
Java插入的代码放入到 #purchase_apply_detail里面:
@Export
@Columns("(img_url,图片)(spec_no,商家编码)(goods_no,货品编号)(goods_name,货品名称)(short_name,货品简称)(spec_name,规格名称)" +
"(spec_code,规格码)(brand_id,品牌)(base_unit_name,基本单位)(unit_name,采购单位)(stock_num,库存数量)(num,采购数量)" +
"(remark,备注)")
@Transforms("(num,goods_count)(stock_num,goods_count)(recommand_num,goods_count)(real_num,goods_count)")
@BindAttributes("rec_id,spec_id,spec_no")
@ServerTransforms("goods_brand(brand_id<),unit_name(base_unit_id+base_unit_name)")
public Response getDetailToUpdateTest(Session session, int applyID) throws SQLException
{
int recommandNum = SettingUtils.getCacheConfig(session, "purchase_apply_recommand_num", 0);
return session.db(false)
.query("SELECT pad.rec_id,gs.img_url,gs.spec_id,gs.spec_no,gg.goods_no,gg.goods_name,"
+ " gg.short_name,gs.spec_name,gs.spec_code,gg.brand_id,gg.unit AS base_unit_id,"
+ " pad.unit AS unit_id,u.name AS unit_name,IFNULL(ss.stock_num,0) AS stock_num,pad.num,"
+ (recommandNum == 1 ? "pad.num-IFNULL(ss.`stock_num`,0)" : "pad.recommand_num")
+ " AS recommand_num,pad.real_num,pad.remark " +
"FROM count_detail pad"
+ " LEFT JOIN zlw_count pa ON pa.rec_id = pad.apply_id"
+ " LEFT JOIN goods_spec gs ON gs.spec_id = pad.spec_id"
+ " LEFT JOIN goods_goods gg ON gg.goods_id = gs.goods_id"
+ " LEFT JOIN cfg_goods_aux_unit u ON u.rec_id = pad.unit"
+ " LEFT JOIN stock_spec ss ON ss.spec_id = pad.spec_id AND ss.warehouse_id = pa.warehouse_id AND ss.defect=0"
+ " WHERE pad.apply_id=?", applyID);
}
purchase.PurchaseApply.getSpecForApplyTestAdapter
@Export
@BindAttributes("spec_no,img_url,goods_id,spec_id")
@ServerTransforms("goods_brand(brand_id<)")
public Response getSpecForApplyTestAdapter(Session session, int specID, short warehouseID) throws SQLException
{// purchase_apply_detail_confirm_view
return session.db(false)
.query("SELECT 0 AS rec_id,gs.spec_id,gs.spec_name,gs.spec_code,gs.spec_no,gs.img_url,gg.goods_id,"
+ " gg.goods_name,gg.goods_no,gg.short_name,gg.brand_id,IFNULL(ss.stock_num,0) AS stock_num"
+ " FROM goods_spec gs LEFT JOIN goods_goods gg ON gg.goods_id = gs.goods_id"
+ " LEFT JOIN stock_spec ss ON ss.spec_id = gs.spec_id AND ss.warehouse_id=? AND ss.defect=0"
+ " WHERE gs.spec_id=?", warehouseID, specID);
}
添加单品代码具体实现代码:(利用Java在后端进行查询数据库进行比
C#
//添加单品
[Click("#btn_add_spec")]
void OnClickAddSpec()
{
var warehouseId = Q("#apply_warehouse_id").IntegerValue;
if(warehouseId == 0)
{
Alert("请选择申请仓库!");
return ;
}
var arg = new GoodsSpecSelectParams{ Multiple=true };
if(IDOK == DoModal(default(GoodsSpecSelectWindow), arg))
{
for(var i = 0; i < arg.SpecIds.Count; i++)
{
var specSelectInfo = Q($"#purchase_apply_detail > tr:not([deleted])[data-spec_id={arg.SpecIds[i]}]");
if(specSelectInfo == null)
{
var purchaseApplydetail = Q("#purchase_apply_detail_new > tr").Clone();
purchaseApplydetail.AppendTo(Q("#purchase_apply_detail")).Bind("purchase.PurchaseApply.getSpecForApplyTestAdapter",//yes
arg.SpecIds[i], warehouseId).SetAttr("data-spec_id", arg.SpecIds[i]).SetAttr("data-rec_id", 0).Field("num").SetValue(1);
//
purchaseApplydetail.Field("real_num").SetState(ElementState.STATE_DISABLED);
purchaseApplydetail.Field("recommand_num").SetState(ElementState.STATE_DISABLED);
if(isRecommandNumSet)
{
var recommandNum = (purchaseApplydetail.Field("num").Value).ToDecimal()-(purchaseApplydetail.Field("stock_num").Value).ToDecimal();
purchaseApplydetail.Field("recommand_num").SetValue(recommandNum.ToString());
//purchaseApplydetail.field("real_num").set_value(0);
}
}
else
{
specSelectInfo.SelectParent( "tr",0).SetAttr("changed");
var num = specSelectInfo.Field("num");
var realNum = specSelectInfo.Field("real_num");
var recommandNum = specSelectInfo.Field("recommand_num");
var updateNum = recommandNum.DecimalValue;
updateNum = updateNum+arg.Numbers[i];
num.SetValue(ModelUtils.ToGoodsNum(num.DecimalValue+arg.Numbers[i]));
realNum.SetValue(ModelUtils.ToGoodsNum(realNum.DecimalValue+arg.Numbers[i]));
recommandNum.SetValue(ModelUtils.ToGoodsNum(updateNum));
specSelectInfo.ScrollToView();
listViewItemSetChecked(specSelectInfo);
}
}
CalcGoodsTotal();
}
}
解释:
这段代码是一个添加单品的功能实现。当点击按钮"#btn_add_spec"时,会执行OnClickAddSpec()函数。
首先,代码获取选择的仓库ID,如果仓库ID为0,则弹出提示框"请选择申请仓库!",并返回。
接下来,创建一个GoodsSpecSelectParams对象arg,并设置其Multiple属性为true。然后通过调用DoModal函数打开一个商品规格选择窗口GoodsSpecSelectWindow,并传入arg作为参数。如果用户在选择窗口中点击了确定按钮(IDOK),则继续执行下面的代码;否则不执行。
在循环中,遍历arg.SpecIds列表中的每个规格ID。首先,通过选择器找到具有相应规格ID的元素specSelectInfo。如果specSelectInfo为null,表示该规格尚未添加到计数单详情表中,则进行以下操作:
- 克隆一个新的tr元素purchaseApplydetail,并将其追加到"#purchase_apply_detail"元素中。
- 绑定数据源为"purchase.PurchaseApply.getSpecForApplyTestAdapter",并传入规格ID和仓库ID作为参数。
- 设置该行元素的"data-spec_id"属性为规格ID,"data-rec_id"属性为0,"num"字段的值为1。
- 如果isRecommandNumSet为true,则计算推荐数量并设置"recommand_num"字段的值。
如果specSelectInfo不为null,表示该规格已经存在于计数单详情表中,则进行以下操作:
- 标记该行元素为"changed"。
- 获取"num"、字段的值。
- 更新数量相关字段的值。
- 将该行元素滚动到可视区域内。
- 选中该行元素。
总之,这段代码实现了向计数单详情表中添加单品的功能。根据传入的规格ID和仓库ID,如果该规格尚未添加到表中,则添加一行新的记录;如果已存在,则更新相应字段的值。
1.4.2 Java:删除单品功能
C#代码
/删除列表
[Click("#btn_del_spec")]
[DblClickTR("#purchase_apply_detail")]
void OnClickDel()
{
if(orderStatus == 20)
{
return ;
}
var goodsList = Q("#purchase_apply_detail");
if(goodsList.NoneSelectedRow())
{
Alert("请选择单品");
return ;
}
if(!Confirm("确定要删除所选单品吗?"))
return ;
List<Element> deletingList = new List<Element>();
goodsList.ForEach(delegate(Element element)
{
if(element.RecId() != 0)
element.SetAttr("deleted").SetState(0, ElementState.STATE_CHECKED);
else
//先标记需要删除tr
deletingList.Add(element);
}, "tr:not(.header):checked");
deletingList.ForEach(e => e.Destroy(false, false));
goodsList.Update().Xcall("fix_seq");
CalcGoodsTotal();
}
- 创建一个空的列表
deletingList
,用于存储需要删除的元素。 - 使用
goodsList.ForEach
方法遍历商品列表中满足特定条件的元素,条件为选择了且不是头部的<tr>
元素。 - 对于满足条件的元素,如果其
RecId()
不等于 0,则设置其属性 "deleted" 的状态为 0 并将其状态设置为已选中(SetState(0, ElementState.STATE_CHECKED)
)。 - 对于不满足条件的元素,将其添加到
deletingList
中。 - 使用
deletingList.ForEach
方法遍历deletingList
列表中的元素。 - 对于每个元素,调用
Destroy(false, false)
方法进行删除操作,其中false, false
表示不触发事件和不执行撤销操作。 - 对
goodsList
进行更新操作,并调用Xcall("fix_seq")
方法。
1.5 选择货品页面可以使用已有页面管理页面要求有对单据进行保存、提交、审核、驳回审核、返回编辑操作。
1.5.1 保存:变成编辑中
使用到的主要函数,保存到表里面数据,并且状态变成编辑中。
public int createTest(Session session, PurchaseApply apply, List<PurchaseApplyDetail> detailInfo, boolean isSubmit)
throws SQLException, AppException
{// SP_PURCHASE_APPLY_INSERT
DbSession db = session.db(false);
if (isSubmit && detailInfo.size() == 0)
throw new AppException("请选择单品");
if (detailInfo.stream().anyMatch(o -> o.getNum().compareTo(BigDecimal.ZERO) < 1))
throw new AppException("采购申请量应大于0");
// 是否开启整数校验
boolean goodsIntCount = SettingUtils.getCacheConfig(session, "gbl_goods_int_count", true);
if (goodsIntCount && detailInfo.stream().anyMatch(o -> !HandUtils.isInteger(o.getNum())))
throw new AppException("采购申请量不为整数");
// 采购申请数量的确认流程
boolean numConfrim = SettingUtils.getCacheConfig(session, "purchase_apply_num_confrim", true);
Byte status = isSubmit ? (numConfrim ? PurchaseApply.STATUS_NEED_CHECK : PurchaseApply.STATUS_NEED_USE)
: PurchaseApply.STATUS_EDIT;
apply.setStatus(status);
apply.setCreatorId(session.getUserId());
db.startTx();
String applyNO = CommonUtils.getSysNO(session, "zlw_count");
int applyID = db.insertBean(
"INSERT INTO zlw_count(purchase_count_no,status,creator_id,warehouse_id,expected_time,remark)"
+ " VALUES(:purchase_count_no,:status,:creator_id,:warehouse_id,:expected_time,:remark);",
apply).intValue();
this.insertLog(session, applyID, "新建采购申请单--" + applyNO);
db.batchUpdateBean("INSERT INTO zlw_count_detail(apply_id,spec_id,num,recommand_num,real_num,remark)"
+ " VALUES(?,:spec_id,:num,:recommand_num,:real_num,:remark)", detailInfo, applyID);
db.update("INSERT INTO zlw_count_log(apply_id,operator_id,remark)"
+ " SELECT pad.apply_id,?,CONCAT('添加单品--商家编码--',gs.spec_no, ' ---数量--- ',pad.num,'状态为编辑中')"
+ " FROM zlw_count_detail pad LEFT JOIN goods_spec gs ON pad.spec_id = gs.spec_id"
+ " WHERE pad.apply_id=?", session.getUserId(), applyID);
if (isSubmit)
this.insertLog(session, applyID, "申请单被提交");
db.commit();
return applyID;
}请你详细进行解释
private void insertLog(Session session, int applyID, String logDetail) throws SQLException
{
session.db(false).update("INSERT INTO zlw_count_log(apply_id,operator_id,remark) VALUES(?,?,?);", applyID,
session.getUserId(), logDetail);
}
解释:
-
首先,该方法接受以下参数:一个会话对象(Session)、一个计数对象(PurchaseApply)、一个计数明细列表(List<PurchaseApplyDetail>)和一个布尔值(isSubmit)。
-
接下来,通过会话对象获取数据库连接(DbSession)。
-
如果isSubmit为true并且计数明细列表为空,则抛出一个异常(AppException),提示用户选择至少一个单品。
-
如果计数明细列表中存在数量小于等于零的明细项,则抛出一个异常(AppException),提示计数申请量应大于零。
-
根据配置项"gbl_goods_int_count"的值,判断是否开启整数校验。如果开启,并且计数明细列表中存在非整数的数量,则抛出一个异常(AppException),提示计数量应为整数。
-
根据配置项"purchase_apply_num_confrim"的值,确定计数数量的确认流程。如果需要确认,则将计数单的状态设置为"待审核",否则设置为"待使用"。如果isSubmit为false,则设置状态为"编辑"。
-
设置申请单的创建者ID为当前会话用户的ID。
-
开启数据库事务。
-
生成计数单的编号(applyNO)。
-
将计数单插入到数据库表"zlw_count"中,返回插入的计数单ID(applyID)。插入操作使用了预编译的SQL语句,将申请单对象的属性映射到对应的数据库字段上。
-
调用insertLog方法,记录日志信息,表示新建了一个采购申请单。
-
使用批处理方式,将计数明细列表中的每个明细项插入到数据库表"zlw_count_detail"中。插入操作同样使用了预编译的SQL语句,将明细项对象的属性映射到对应的数据库字段上。
-
使用普通的SQL语句,将操作者ID、申请单ID和备注信息插入到数据库表"zlw_count_log"中。这条SQL语句是一个SELECT语句,从"zlw_count_detail"表和"goods_spec"表中联合查询数据,并将查询结果插入到"zlw_count_log"表中。
-
如果isSubmit为true,则调用insertLog方法,记录日志信息,表示申请单被提交。
-
提交数据库事务。
-
返回申请单ID(applyID)。
总体来说,该方法的功能是创建计数单,并将相关信息插入到数据库中。它涉及到数据库操作、日志记录等功能,并根据一些条件进行校验和状态设置。
"purchase.PurchaseApply.updateTest
代码:
public int updateTest(Session session, PurchaseApply apply, List<PurchaseApplyDetail> detailInfo,
List<Integer> deleteIDs, boolean isSubmit) throws SQLException, AppException
{// SP_PURCHASE_APPLY_UPDATE
DbSession db = session.db(false);
// 是否开启整数校验
boolean goodsIntCount = SettingUtils.getCacheConfig(session, "gbl_goods_int_count", true);
if (goodsIntCount && detailInfo.stream().anyMatch(
o -> (o.getRecId() == 0 || deleteIDs.indexOf(o.getRecId()) > 0) && !HandUtils.isInteger(o.getNum())))
throw new AppException("采购申请量不为整数");
db.startTx();
PurchaseApply oldApply = db.query("SELECT * FROM zlw_count WHERE rec_id=? FOR UPDATE", PurchaseApply.class,
apply.getRecId());
if (oldApply == null)
throw new AppException("要确认的申请单不存在");
if (oldApply.getStatus() != PurchaseApply.STATUS_EDIT)
throw new AppException("采购申请单不是编辑中状态");
if (!oldApply.getVersionId().equals(apply.getVersionId()))
throw new AppException("采购申请单已被其他人修改,请重新修改");
if (detailInfo.stream().anyMatch(o -> o.getNum().compareTo(BigDecimal.ZERO) < 1))
throw new AppException("采购申请量应大于0");
String sql = "UPDATE zlw_count SET warehouse_id=:warehouse_id,creator_id=:creator_id,"
+ " expected_time=:expected_time,remark=:remark,version_id=:version_id WHERE rec_id=:rec_id";
if(!SqlUtils.checkEqualsByFields(sql, oldApply, apply, "version_id"))
{
apply.setVersionId(oldApply.getVersionId() + 1);
db.updateBean(sql, apply);
this.updateLog(session, apply.getRecId(), apply, oldApply);
}
// 处理删除的
if (deleteIDs.size() > 0)
{
db.batchUpdateList(
"INSERT INTO zlw_count_log(apply_id,operator_id,remark)"
+ " SELECT pad.apply_id,?,CONCAT('删除单品---商家编码----',spec_no)"
+ " FROM zlw_count_detail pad LEFT JOIN goods_spec gs ON pad.spec_id = gs.spec_id"
+ " WHERE pad.rec_id=? AND pad.apply_id=?",
session.getUserId(), deleteIDs, apply.getRecId());
db.batchUpdateList("DELETE FROM zlw_count_detail WHERE rec_id=? AND apply_id=?", deleteIDs,
apply.getRecId());
}
// 更新明细
sql = "UPDATE zlw_count_detail SET num=:num,recommand_num=:recommand_num,"
+ " real_num=:real_num,remark=:remark WHERE rec_id=:rec_id AND apply_id=?";
Method[] methods = SqlUtils.getUpdateFields(sql, PurchaseApplyDetail.class, "rec_id");
List<PurchaseApplyDetail> insertDetailInfo = new ArrayList<PurchaseApplyDetail>();
for (PurchaseApplyDetail detail : detailInfo)
{
if (detail.getRecId() == 0)
{// 新建
insertDetailInfo.add(detail);
String specNO = db.get("SELECT spec_no FROM goods_spec WHERE spec_id=?", detail.getSpecId());
this.insertLog(session, apply.getRecId(), "添加单品----商家编码----" + specNO + "----数量----" + detail.getNum());
continue;
}
PurchaseApplyDetail oldDetail = db.query(
"SELECT * FROM zlw_count_detail WHERE rec_id=? AND apply_id=?",
PurchaseApplyDetail.class, detail.getRecId(), apply.getRecId());
if(!SqlUtils.checkEqualsByFields(methods, oldDetail, detail))
{
db.updateBean(sql, detail, apply.getRecId());
this.updateDetailLog(session, apply.getRecId(), detail, oldDetail);
}
}
db.batchUpdateBean(
"INSERT INTO zlw_count_detail(apply_id,spec_id,num,recommand_num,real_num,remark)"
+ " VALUES(?,:spec_id,:num,:recommand_num,:real_num,:remark)",
insertDetailInfo, apply.getRecId());
if (isSubmit)
{
// 采购申请数量的确认流程
boolean numConfrim = SettingUtils.getCacheConfig(session, "purchase_apply_num_confrim", true);
Byte status = numConfrim ? PurchaseApply.STATUS_NEED_CHECK : PurchaseApply.STATUS_NEED_USE;
db.update("UPDATE zlw_count SET status = ? WHERE rec_id=?", status, apply.getRecId());
this.insertLog(session, apply.getRecId(), "采购单提交");
}
db.commit();
return apply.getVersionId();
}
-
首先,代码通过数据库会话(
session
)和传入的参数进行初始化,并获取数据库连接(db
)。 -
接下来,代码检查是否开启了整数校验功能。如果开启了整数校验,并且申请的采购数量不是整数,则抛出异常。
-
代码开始一个数据库事务(
db.startTx()
),以确保操作的原子性。 -
通过查询数据库,获取要更新的采购申请的旧数据(
oldApply
)。如果旧数据不存在,则抛出异常。 -
检查旧的采购申请的状态是否为编辑中状态(
PurchaseApply.STATUS_EDIT
)。如果不是编辑中状态,则抛出异常。 -
检查传入的申请单版本号与旧申请单版本号是否一致。如果不一致,则抛出异常。
-
检查申请单中的采购数量是否大于0。如果小于等于0,则抛出异常。
-
如果申请单的部分字段发生了变化,则执行更新操作。首先构建更新语句(
sql
),然后使用db.updateBean
方法执行更新。更新完成后,调用updateLog
方法记录日志。 -
处理要删除的采购申请明细。首先将删除操作记录插入日志表(
zlw_count_log
),然后执行删除操作。 -
更新采购申请明细。首先构建更新语句(
sql
),然后使用db.updateBean
方法执行更新。更新完成后,调用updateDetailLog
方法记录日志。 -
对于新增的采购申请明细,将其插入数据库表(
zlw_count_detail
)。 -
如果参数
isSubmit
为true
,则表示提交了采购申请。根据配置项判断是否需要进行采购申请数量的确认流程。如果需要确认,则将采购申请的状态设置为待审核(PurchaseApply.STATUS_NEED_CHECK
),否则设置为待使用(PurchaseApply.STATUS_NEED_USE
)。同时,记录提交日志。 -
提交事务(
db.commit()
)。 -
返回申请单的版本号(
apply.getVersionId()
)。
总体来说,这段代码实现了更新采购申请的功能,包括更新申请单信息、删除申请明细、更新申请明细和新增申请明细等操作,并支持采购申请的提交流程。在每次操作之前,都进行了必要的校验和检查,并记录了相应的日志。
1.5.2 提交 (同上)只是传入了true。变成了待审核。
1.5.3 审核
代码:点击审核后跳入这个
[Click("#btn_confirm")]
void OnClickConfirm()
{
var detailList = Q("#purchase_apply_detail");
var curVersionId = Q("#purchase_apply").GetData("version_id", 0);
var status = Q("#purchase_apply").GetData("status", 0);
if(purchaseApplyId == 0)
{
Alert("无效的计数单");
return ;
}
if (status != 20)
{
Alert("计数单不是待审核状态");
return ;
}
// 判断最终计数量是否大于0
var flag1 = "";
detailList.ForEach(delegate(Element element)
{
var realNum = (element.Field("real_num").Value).ToDecimal();
if(realNum <= decimal.Zero)
{
flag1 = "实际计数量应大于0";
element.SetStyleAttr("color", "red");
}
else
{
element.SetStyleAttr("color", "black");
}
}
, "tr:not([deleted]):not(.header)");
if(flag1 != "")
{
Alert(flag1);
return ;
}
//记录变动的货品条目信息
var goodsListData = detailList.Fields("tr[changed]:not([deleted])", "rec_id", "num", "recommand_num", "real_num");
try
{
var versionId = (int)DB.Call("purchase.PurchaseApply.confirmTest", purchaseApplyId, goodsListData, curVersionId);//修改
Q("#purchase_apply").SetData("version_id", versionId);
}
catch(DbException e)
{
ShowException(e);
return ;
}
EndDialog(IDOK);
return ;
}
"purchase.PurchaseApply.confirmTest",
public int confirmTest(Session session, int applyID, List<PurchaseApplyDetail> detailInfo, int versionId)
throws SQLException, AppException
{// SP_PURCHASE_APPLY_CONFIRM
DbSession db = session.db(false);
// 是否开启整数校验
boolean goodsIntCount = SettingUtils.getCacheConfig(session, "gbl_goods_int_count", true);
if (goodsIntCount && detailInfo.stream()
.anyMatch(o -> !HandUtils.isInteger(o.getRealNum()) || !HandUtils.isInteger(o.getRecommandNum())))
throw new AppException("计数量不为整数");
db.startTx();
PurchaseApply apply = db.query("SELECT * " +
"FROM zlw_count WHERE rec_id = ? FOR UPDATE", PurchaseApply.class, applyID);
if (apply == null)
throw new AppException("要确认的计数单不存在");
if (apply.getStatus() != PurchaseApply.STATUS_NEED_CHECK)
throw new AppException("计数单不是待确认状态");
if (!apply.getVersionId().equals(versionId))
throw new AppException("计数单正在被其他人修改,请重试");
if (detailInfo.stream().anyMatch(o -> o.getNum().compareTo(BigDecimal.ZERO) == 0))
throw new AppException("计数单的实际数量不能小于等于0,请修改");
versionId++;
// 更新状态
db.update("UPDATE zlw_count " +
"SET status=?,version_id=? WHERE rec_id=?", PurchaseApply.STATUS_NEED_USE,
versionId, applyID);
this.insertLog(session, applyID, "审核成功,状态为已审核");
db.commit();
return versionId;
}
1.5.4 驳回 (已审核->待审核)(待审核->编辑中)
[Click("#btn_back")]
void OnClickBackStatus()
{
BatchProcess("purchase.PurchaseApply.reCheckTest", "确定驳回选中的申请单?", "申请单驳回失败原因:");
}
public OrderErrorList reCheckTest(Session session, List<Integer> applyIDs) throws SQLException
{// SP_PURCHASE_APPLY_STATUS_BACK
DbSession db = session.db(false);
List<ErrorMessage> errorList = new ArrayList<ErrorMessage>();
// 确认采购申请量流程
boolean numConfrim = SettingUtils.getCacheConfig(session, "purchase_apply_num_confrim", true);
for (int applyID : applyIDs)
{
db.startTx();
PurchaseApply Apply = db.query(
// "SELECT purchase_apply_no,status " +
// "FROM purchase_apply WHERE rec_id=? FOR UPDATE",
"SELECT purchase_count_no,status " +
"FROM zlw_count WHERE rec_id=? FOR UPDATE",
PurchaseApply.class, applyID);
if (Apply == null)
{
errorList.add(new ErrorMessage(applyID, "", "找不到对应的计数单"));
db.rollback();
continue;
}
String log = "";
int toStatus = Apply.getStatus();
if (toStatus <= PurchaseApply.STATUS_EDIT || toStatus >= PurchaseApply.STATUS_SOME_USE)
{
errorList.add(new ErrorMessage(applyID, Apply.getPurchaseApplyNo(), "计数单状态不是待审核或已审核"));
db.rollback();
continue;
}
if (toStatus == PurchaseApply.STATUS_NEED_CHECK)
{
log = "将计数单从待审核状态驳回到编辑状态";
toStatus = PurchaseApply.STATUS_EDIT;
}
if (toStatus == PurchaseApply.STATUS_NEED_USE)
{
if (!numConfrim)
{
log = "将计数单从已审核状态驳回到编辑状态";
toStatus = PurchaseApply.STATUS_EDIT;
}
else
{
log = "将采购申请单从已审核状态驳回到待审核状态";
toStatus = PurchaseApply.STATUS_NEED_CHECK;
}
}
// db.update("UPDATE purchase_apply SET status=? WHERE rec_id=?", toStatus, applyID);
db.update("UPDATE zlw_count SET status=? WHERE rec_id=?", toStatus, applyID);
this.insertLog(session, applyID, log);
db.commit();
} // end for(int applyID:applyIDs)
return OrderErrorList.as(errorList);
}
1.5.5 取消
public OrderErrorList cancelTest(Session session, List<Integer> applyIDs) throws SQLException
{// SP_PURCHASE_APPLY_CANCLE
DbSession db = session.db(false);
List<ErrorMessage> errorList = new ArrayList<ErrorMessage>();
for (int applyID : applyIDs)
{
db.startTx();
PurchaseApply Apply = db.query(
"SELECT purchase_count_no,status FROM zlw_count WHERE rec_id=? FOR UPDATE",
PurchaseApply.class, applyID);
if (Apply == null)
{
errorList.add(new ErrorMessage(applyID, "", "找不到对应的计数单"));
db.rollback();
continue;
}
if (Apply.getStatus() != PurchaseApply.STATUS_EDIT && Apply.getStatus() != PurchaseApply.STATUS_NEED_CHECK)
{
errorList.add(new ErrorMessage(applyID, Apply.getPurchaseApplyNo(), "计数请单状态不是编辑中或待审核"));
db.rollback();
continue;
}
db.update("UPDATE zlw_count SET status=? WHERE rec_id=?", PurchaseApply.STATUS_CANCEL, applyID);
this.insertLog(session, applyID, "取消了计数单");
db.commit();
return OrderErrorList.as(errorList);
}
该方法首先通过Session对象获取一个DbSession对象,然后遍历所有要取消的计数单ID。在每次循环中,它会开启一个数据库事务(db.startTx()),并查询对应ID的计数单对象(PurchaseApply)。
如果查询结果为空,则说明找不到对应的计数单,此时会将该计数单ID、空字符串和错误信息添加到错误列表中,并回滚事务(db.rollback()),继续下一个循环。
如果查询结果不为空,则判断计数单的状态是否为“编辑中”或“待审核”。如果不是,则将该计数单ID、计数单号和错误信息添加到错误列表中,并回滚事务,继续下一个循环。
如果计数单状态符合要求,则将该计数单的状态设置为“已取消”(PurchaseApply.STATUS_CANCEL),并记录一条日志(insertLog方法)。最后提交事务(db.commit())。
最终,该方法会返回一个OrderErrorList对象,其中包含所有取消失败的计数单ID、计数单号和错误信息。
1.6 搜索的实现代码
[Click("#btn_search")]
void OnClickSearch()
{
// 将特定元素的内容转化为可用于查询或搜索的参数
// 向数据库请求数据并绑定到指定元素上
var queryParams = this.ToQueryParam(".flat_bar");
Q("#purchase_apply_list").DbPageBind("purchase.PurchaseApply.queryTest", queryParams);
}
public Response queryTest(Session session, Map<String, Object> params, Pager pager) throws SQLException
{
DbSession db = session.db(false);
Where where = new Where(params, session)
{
{
equal("purchase_count_no", "pa.purchase_count_no");
equal("warehouse_id", "pa.warehouse_id");
in("status", "pa.status");
equal("creator_id", "pa.creator_id");
equal("spec_no", "gs.spec_no");
equal("goods_no", "gg.goods_no");
equalOrLike("goods_short_name_likeq", "short_name", "gg.short_name");
dateBetween("create_begin", "create_end", "pa.created");
dateBetween("excepted_begin", "excepted_end", "pa.expected_time");
}
}.orderBy("pa.rec_id DESC");// pa.modified DESC
Table table = new Table("zlw_count pa", "pa.rec_id", where)
{
{
innerJoin("zlw_count_detail pad", "pad.apply_id = pa.rec_id", "gs.,gg.");
innerJoin("goods_spec gs", "gs.spec_id = pad.spec_id", "gs.,gg.");
innerJoin("goods_goods gg", "gg.goods_id = gs.goods_id", "gg.");
}
}.extraJoin("zlw_count_detail pad", "pad.apply_id = pa.rec_id");
table.setDistinct(where.contains("gs.,gg.,pg."));
String fields = "pa.rec_id,pa.purchase_count_no,pa.status,pa.creator_id,pa.warehouse_id,"
+ " IFNULL(sum(pad.real_num),0) as real_num,IFNULL(sum(pad.ref_num),0) as ref_num,"
+ " IFNULL(sum(pad.real_num-pad.ref_num),0) as unref_num,pa.expected_time as expected_time,"
+ " pa.remark,pa.modified,pa.created";
Where extraWhere = new Where(params, session).groupBy("pa.rec_id").orderBy("pa.rec_id DESC");// pa.modified
// DESC
table.setOutputFields(fields);
return SqlUtils.pageQuery(db, pager, table, where, extraWhere);
}