计数单编写

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来记录每个计数单的明细信息,这样可以带来以下好处:

  1. 数据结构更清晰:将计数单的基本信息和明细信息分别存储在两张表中,可以使数据结构更加清晰,易于理解和维护。

  2. 方便查询和统计:将计数单的明细信息单独存储在count_detail表中,可以方便地进行查询和统计,例如可以按照采购申请单、规格等字段进行筛选和排序,从而更加方便地了解计数单的具体情况。

  3. 易于扩展:如果需要添加新的字段或者修改字段类型,单独维护明细表count_detail就会更加方便,不会影响到计数单基本信息表count。

  4. 降低数据冗余:将计数单的明细信息单独存储在count_detail表中,避免了重复存储计数单的基本信息,可以降低数据冗余,提高数据库的性能和存储效率。

综上所述,建立count_detail表可以使数据结构更清晰,方便查询和统计,易于扩展,同时也可以降低数据冗余,提高数据库的性能和存储效率。

  1. 数据结构清晰:通过将采购申请相关的数据拆分到不同的表中,可以使数据结构更加清晰明确。每个表都专注于存储特定的信息,例如count表存储采购申请单的基本信息,count_detail表存储采购申请明细的信息,count_log表存储采购申请的操作日志。这种拆分可以提高数据的可读性和可维护性。

  2. 数据一致性:通过使用关联字段(如apply_id)将不同表中的数据关联起来,可以确保数据的一致性。例如,count_detail表中的每条记录都与count表中的某个采购申请单关联,这样可以避免出现孤立的数据或数据冗余。同时,通过在count表中使用版本号字段(version_id),可以实现乐观锁机制,确保数据的更新是基于最新的版本,避免并发操作导致的数据冲突。

  3. 查询性能优化:通过合理地设计表的索引,可以提高查询性能。例如,在count表中可以为常用查询条件(如statuscreator_id等)创建索引,以加快查询速度。此外,通过合理使用关联查询(JOIN)等操作,可以在多个表之间进行高效的数据检索和关联操作。

  4. 数据统计与分析:由于数据被拆分到不同的表中,可以更方便地进行数据统计和分析。例如,可以通过对count_detail表中的数量字段进行汇总,得到某个采购申请单的总数量。同时,可以根据pcount_log表中的操作记录,进行操作日志的查询和分析,了解采购申请的操作历史。

  5. 扩展性和灵活性:通过将采购申请相关的数据拆分到不同的表中,可以更容易地进行系统扩展和功能调整。例如,如果需要增加新的采购申请属性或者关联其他表,只需修改相应的表结构,而不会对整个系统产生较大的影响。这种表的设计使系统更加灵活,方便适应未来的需求变化。

总的来说,根据上述三个表建立计数开单的开发方案,从表的角度来看,可以提供清晰的数据结构、数据一致性、查询性能优化、数据统计与分析、扩展性和灵活性等好处。这些好处有助于提高系统的可维护性、性能和可扩展性,为用户提供更好的使用体验和数据管理能力。

1.1.1.5 查数据库的Java拼接过程:

查询方法的一般格式:(查询有很多种,这里以一般页面载入的时候使用的分页查询为例)

public Response query(Session session, Map params, Pager pager)

如果使用分页查询,其中参数 Session session, Pager pager是固定的,中间的参数是你传入的参数,个数自己控制

流程:

1.构造where,

2.构造table

3.添加查询字段

1.2 页面设计

对前端协调沟通后的页面设计进行了数据库表的建立。(答出数据库表的字段对应的前端的位置)

页面能够选择单品,选择货品页面可以使用已有页面

页面要求有对单据进行保存,提交,审核、驳回审核、返回编辑操作,

能够进行针对单据、货品、单品的常用搜索

单据要求至少有编辑中、待审核、已审核状态

单据操作必须有日志,对应的状态校验,数量和状态检查等 需对可能产生的异常操作进行校验/提示/处理

1.3 页面逻辑 C#(暂时不考虑)

对于进行Java后端进行的数据库的数据查询,前端如何进行处理,进行业务方面的问题的协调。

添加单品
删除单品

#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,表示该规格尚未添加到计数单详情表中,则进行以下操作:

  1. 克隆一个新的tr元素purchaseApplydetail,并将其追加到"#purchase_apply_detail"元素中。
  2. 绑定数据源为"purchase.PurchaseApply.getSpecForApplyTestAdapter",并传入规格ID和仓库ID作为参数。
  3. 设置该行元素的"data-spec_id"属性为规格ID,"data-rec_id"属性为0,"num"字段的值为1。
  4. 如果isRecommandNumSet为true,则计算推荐数量并设置"recommand_num"字段的值。

如果specSelectInfo不为null,表示该规格已经存在于计数单详情表中,则进行以下操作:

  1. 标记该行元素为"changed"。
  2. 获取"num"、字段的值。
  3. 更新数量相关字段的值。
  4. 将该行元素滚动到可视区域内。
  5. 选中该行元素。

总之,这段代码实现了向计数单详情表中添加单品的功能。根据传入的规格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 deletingList = new List();
			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();
		}
  1. 创建一个空的列表 deletingList,用于存储需要删除的元素。
  2. 使用 goodsList.ForEach 方法遍历商品列表中满足特定条件的元素,条件为选择了且不是头部的  元素。
  3. 对于满足条件的元素,如果其 RecId() 不等于 0,则设置其属性 "deleted" 的状态为 0 并将其状态设置为已选中(SetState(0, ElementState.STATE_CHECKED))。
  4. 对于不满足条件的元素,将其添加到 deletingList 中。
  5. 使用 deletingList.ForEach 方法遍历 deletingList 列表中的元素。
  6. 对于每个元素,调用 Destroy(false, false) 方法进行删除操作,其中 false, false 表示不触发事件和不执行撤销操作。
  7. 对 goodsList 进行更新操作,并调用 Xcall("fix_seq") 方法。

1.5   选择货品页面可以使用已有页面管理页面要求有对单据进行保存、提交、审核、驳回审核、返回编辑操作。

1.5.1 保存:变成编辑中

使用到的主要函数,保存到表里面数据,并且状态变成编辑中。

public int createTest(Session session, PurchaseApply apply, List 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);
	}

 解释:

  1. 首先,该方法接受以下参数:一个会话对象(Session)、一个计数对象(PurchaseApply)、一个计数明细列表(List)和一个布尔值(isSubmit)。

  2. 接下来,通过会话对象获取数据库连接(DbSession)。

  3. 如果isSubmit为true并且计数明细列表为空,则抛出一个异常(AppException),提示用户选择至少一个单品。

  4. 如果计数明细列表中存在数量小于等于零的明细项,则抛出一个异常(AppException),提示计数申请量应大于零。

  5. 根据配置项"gbl_goods_int_count"的值,判断是否开启整数校验。如果开启,并且计数明细列表中存在非整数的数量,则抛出一个异常(AppException),提示计数量应为整数。

  6. 根据配置项"purchase_apply_num_confrim"的值,确定计数数量的确认流程。如果需要确认,则将计数单的状态设置为"待审核",否则设置为"待使用"。如果isSubmit为false,则设置状态为"编辑"。

  7. 设置申请单的创建者ID为当前会话用户的ID。

  8. 开启数据库事务。

  9. 生成计数单的编号(applyNO)。

  10. 将计数单插入到数据库表"zlw_count"中,返回插入的计数单ID(applyID)。插入操作使用了预编译的SQL语句,将申请单对象的属性映射到对应的数据库字段上。

  11. 调用insertLog方法,记录日志信息,表示新建了一个采购申请单。

  12. 使用批处理方式,将计数明细列表中的每个明细项插入到数据库表"zlw_count_detail"中。插入操作同样使用了预编译的SQL语句,将明细项对象的属性映射到对应的数据库字段上。

  13. 使用普通的SQL语句,将操作者ID、申请单ID和备注信息插入到数据库表"zlw_count_log"中。这条SQL语句是一个SELECT语句,从"zlw_count_detail"表和"goods_spec"表中联合查询数据,并将查询结果插入到"zlw_count_log"表中。

  14. 如果isSubmit为true,则调用insertLog方法,记录日志信息,表示申请单被提交。

  15. 提交数据库事务。

  16. 返回申请单ID(applyID)。

总体来说,该方法的功能是创建计数单,并将相关信息插入到数据库中。它涉及到数据库操作、日志记录等功能,并根据一些条件进行校验和状态设置。

"purchase.PurchaseApply.updateTest

代码:

  

  public int updateTest(Session session, PurchaseApply apply, List detailInfo,
                      List 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 insertDetailInfo = new ArrayList();
        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();
    }
  1. 首先,代码通过数据库会话(session)和传入的参数进行初始化,并获取数据库连接(db)。

  2. 接下来,代码检查是否开启了整数校验功能。如果开启了整数校验,并且申请的采购数量不是整数,则抛出异常。

  3. 代码开始一个数据库事务(db.startTx()),以确保操作的原子性。

  4. 通过查询数据库,获取要更新的采购申请的旧数据(oldApply)。如果旧数据不存在,则抛出异常。

  5. 检查旧的采购申请的状态是否为编辑中状态(PurchaseApply.STATUS_EDIT)。如果不是编辑中状态,则抛出异常。

  6. 检查传入的申请单版本号与旧申请单版本号是否一致。如果不一致,则抛出异常。

  7. 检查申请单中的采购数量是否大于0。如果小于等于0,则抛出异常。

  8. 如果申请单的部分字段发生了变化,则执行更新操作。首先构建更新语句(sql),然后使用db.updateBean方法执行更新。更新完成后,调用updateLog方法记录日志。

  9. 处理要删除的采购申请明细。首先将删除操作记录插入日志表(zlw_count_log),然后执行删除操作。

  10. 更新采购申请明细。首先构建更新语句(sql),然后使用db.updateBean方法执行更新。更新完成后,调用updateDetailLog方法记录日志。

  11. 对于新增的采购申请明细,将其插入数据库表(zlw_count_detail)。

  12. 如果参数isSubmittrue,则表示提交了采购申请。根据配置项判断是否需要进行采购申请数量的确认流程。如果需要确认,则将采购申请的状态设置为待审核(PurchaseApply.STATUS_NEED_CHECK),否则设置为待使用(PurchaseApply.STATUS_NEED_USE)。同时,记录提交日志。

  13. 提交事务(db.commit())。

  14. 返回申请单的版本号(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 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 applyIDs) throws SQLException
	{// SP_PURCHASE_APPLY_STATUS_BACK
		DbSession db = session.db(false);
		List errorList = new ArrayList();
		// 确认采购申请量流程
		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 applyIDs) throws SQLException
	{// SP_PURCHASE_APPLY_CANCLE
		DbSession db = session.db(false);
		List errorList = new ArrayList();
		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 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);
	}

你可能感兴趣的:(数据库,算法,数据结构)