// 交违约金/撤销交违约金 // parameters: // strReaderBarcode 如果功能是"undo",可以将此参数设置为null。如果此参数不为null,则软件要进行核对,如果不是这个读者的已付违约金记录,则要报错 // strAmerceItemIdList id列表, 以逗号分割 // 权限:需要有amerce/amercemodifyprice/amerceundo/amercemodifycomment等权限 // 日志: // 要产生日志 // return: // result.Value 0 成功;1 部分成功(result.ErrorInfo中有信息) public LibraryServerResult Amerce( SessionInfo sessioninfo, string strFunction, string strReaderBarcode, AmerceItem[] amerce_items, out AmerceItem[] failed_items, out string strReaderXml) { strReaderXml = ""; failed_items = null; LibraryServerResult result = new LibraryServerResult(); if (String.Compare(strFunction, "amerce", true) == 0) { // 权限字符串 if (StringUtil.IsInList("amerce", sessioninfo.RightsOrigin) == false) { result.Value = -1; result.ErrorInfo = "交违约金操作被拒绝。不具备 amerce 权限。"; result.ErrorCode = ErrorCode.AccessDenied; return result; } } if (String.Compare(strFunction, "modifyprice", true) == 0) { // 权限字符串 if (StringUtil.IsInList("amercemodifyprice", sessioninfo.RightsOrigin) == false) { result.Value = -1; result.ErrorInfo = "修改违约金额的操作被拒绝。不具备 amercemodifyprice 权限。"; result.ErrorCode = ErrorCode.AccessDenied; return result; } } if (String.Compare(strFunction, "modifycomment", true) == 0) { /* // 权限字符串 if (StringUtil.IsInList("amercemodifycomment", sessioninfo.RightsOrigin) == false) { result.Value = -1; result.ErrorInfo = "修改违约金之注释的操作被拒绝。不具备 amercemodifycomment 权限。"; result.ErrorCode = ErrorCode.AccessDenied; return result; } * */ } if (String.Compare(strFunction, "undo", true) == 0) { // 权限字符串 if (StringUtil.IsInList("amerceundo", sessioninfo.RightsOrigin) == false) { result.Value = -1; result.ErrorInfo = "撤销交违约金操作被拒绝。不具备 amerceundo 权限。"; result.ErrorCode = ErrorCode.AccessDenied; return result; } } if (String.Compare(strFunction, "rollback", true) == 0) { // 权限字符串 if (StringUtil.IsInList("amerce", sessioninfo.RightsOrigin) == false) { result.Value = -1; result.ErrorInfo = "撤回交违约金事务的操作被拒绝。不具备 amerce 权限。"; result.ErrorCode = ErrorCode.AccessDenied; return result; } } if (strFunction != "rollback") { // 看看amerce_items中是否有价格变更或注释变更的情况 bool bHasNewPrice = false; bool bHasOverwriteComment = false; // NewComment具有、并且为覆盖。也就是说包括NewPrice和NewComment同时具有的情况 for (int i = 0; i < amerce_items.Length; i++) { AmerceItem item = amerce_items[i]; // NewPrice域中有值 if (String.IsNullOrEmpty(item.NewPrice) == false) { bHasNewPrice = true; } // NewComment域中有值 if (String.IsNullOrEmpty(item.NewComment) == false) { string strNewComment = item.NewComment; bool bAppend = true; if (string.IsNullOrEmpty(strNewComment) == false && strNewComment[0] == '<') { bAppend = false; strNewComment = strNewComment.Substring(1); } else if (string.IsNullOrEmpty(strNewComment) == false && strNewComment[0] == '>') { bAppend = true; strNewComment = strNewComment.Substring(1); } if (bAppend == false) bHasOverwriteComment = true; } } // 如果要变更价格,则需要额外的amercemodifyprice权限。 // amercemodifyprice在功能amerce和modifyprice中都可能用到,关键是看是否提交了有新价格的参数 if (bHasNewPrice == true) { if (StringUtil.IsInList("amercemodifyprice", sessioninfo.RightsOrigin) == false) { result.Value = -1; result.ErrorInfo = "含有价格变更要求的交违约金操作被拒绝。不具备 amercemodifyprice 权限。(仅仅具备 amerce 权限还不够的)"; result.ErrorCode = ErrorCode.AccessDenied; return result; } } if (bHasOverwriteComment == true) { // 如果有了amerce权限,则暗含有了amerceappendcomment的权限 if (StringUtil.IsInList("amercemodifycomment", sessioninfo.RightsOrigin) == false) { result.Value = -1; result.ErrorInfo = "含有违约金注释(覆盖型)变更要求的操作被拒绝。不具备 amercemodifycomment 权限。(仅仅具备 amerce 权限还不够的)"; result.ErrorCode = ErrorCode.AccessDenied; return result; } } } int nRet = 0; string strError = ""; RmsChannel channel = sessioninfo.Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; goto ERROR1; } if (String.Compare(strFunction, "amerce", true) != 0 && String.Compare(strFunction, "undo", true) != 0 && String.Compare(strFunction, "modifyprice", true) != 0 && String.Compare(strFunction, "modifycomment", true) != 0 && String.Compare(strFunction, "rollback", true) != 0) { result.Value = -1; result.ErrorInfo = "未知的strFunction参数值 '" + strFunction + "'"; result.ErrorCode = ErrorCode.InvalidParameter; return result; } // 如果是undo, 需要先检索出指定id的违约金库记录,然后从记录中得到<readerBarcode>,和参数核对 if (String.Compare(strFunction, "undo", true) == 0) { // UNDO违约金交纳 // return: // -1 error // 0 succeed // 1 部分成功。strError中有报错信息 nRet = UndoAmerces( sessioninfo, strReaderBarcode, amerce_items, out failed_items, out strReaderXml, out strError); if (nRet == -1) goto ERROR1; // 2009/10/10 changed result.Value = nRet; if (nRet == 1) result.ErrorInfo = strError; return result; } // 回滚 // 2009/7/14 if (String.Compare(strFunction, "rollback", true) == 0) { if (amerce_items != null) { strError = "调用rollback功能时amerce_item参数必须为空"; goto ERROR1; } if (sessioninfo.AmerceIds == null || sessioninfo.AmerceIds.Count == 0) { strError = "当前没有可以rollback的违约金事项"; goto ERROR1; } // strReaderBarcode参数值一般为空即可。如果有值,则要求和SessionInfo对象中储存的最近一次的Amerce操作读者证条码号一致 if (String.IsNullOrEmpty(strReaderBarcode) == false) { if (sessioninfo.AmerceReaderBarcode != strReaderBarcode) { strError = "调用rollback功能时strReaderBarcode参数和最近一次Amerce操作的读者证条码号不一致"; goto ERROR1; } } amerce_items = new AmerceItem[sessioninfo.AmerceIds.Count]; for (int i = 0; i < sessioninfo.AmerceIds.Count; i++) { AmerceItem item = new AmerceItem(); item.ID = sessioninfo.AmerceIds[i]; amerce_items[i] = item; } // UNDO违约金交纳 // return: // -1 error // 0 succeed // 1 部分成功。strError中有报错信息 nRet = UndoAmerces( sessioninfo, sessioninfo.AmerceReaderBarcode, amerce_items, out failed_items, out strReaderXml, out strError); if (nRet == -1 || nRet == 1) goto ERROR1; // 清空ids sessioninfo.AmerceIds = new List<string>(); sessioninfo.AmerceReaderBarcode = ""; result.Value = 0; return result; } // 加读者记录锁 #if DEBUG_LOCK_READER this.WriteErrorLog("Amerce 开始为读者加写锁 '" + strReaderBarcode + "'"); #endif this.ReaderLocks.LockForWrite(strReaderBarcode); try { // 读入读者记录 strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // sessioninfo.Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { result.Value = -1; result.ErrorInfo = "读者证条码号 '" + strReaderBarcode + "' 不存在"; result.ErrorCode = ErrorCode.ReaderBarcodeNotFound; return result; } if (nRet == -1) { strError = "读入读者记录时发生错误: " + strError; goto ERROR1; } // 所操作的读者库德馆代码 string strLibraryCode = ""; // 看看读者记录所从属的读者库的馆代码,是否被当前用户管辖 if (String.IsNullOrEmpty(strOutputReaderRecPath) == false) { // 获得读者库的馆代码 // return: // -1 出错 // 0 成功 nRet = GetLibraryCode( strOutputReaderRecPath, out strLibraryCode, out strError); if (nRet == -1) goto ERROR1; // 检查当前操作者是否管辖这个读者库 // 观察一个读者记录路径,看看是不是在当前用户管辖的读者库范围内? if (this.IsCurrentChangeableReaderPath(strOutputReaderRecPath, sessioninfo.LibraryCodeList) == false) { strError = "读者记录路径 '" + strOutputReaderRecPath + "' 从属的读者库不在当前用户管辖范围内"; goto ERROR1; } } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // 准备日志DOM XmlDocument domOperLog = new XmlDocument(); domOperLog.LoadXml("<root />"); DomUtil.SetElementText(domOperLog.DocumentElement, "libraryCode", strLibraryCode); // 读者所在的馆代码 DomUtil.SetElementText(domOperLog.DocumentElement, "operation", "amerce"); // 具体动作 DomUtil.SetElementText(domOperLog.DocumentElement, "action", strFunction.ToLower()); // 读者证条码号 DomUtil.SetElementText(domOperLog.DocumentElement, "readerBarcode", strReaderBarcode); // List<string> AmerceRecordXmls = null; List<string> CreatedNewPaths = null; List<string> Ids = null; string strOperTimeString = this.Clock.GetClock(); // RFC1123格式 bool bReaderDomChanged = false; // 读者dom是否发生了变化,需要回存 { // 在日志中保留旧的读者记录 XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement, "oldReaderRecord", strReaderXml); DomUtil.SetAttr(node, "recPath", strOutputReaderRecPath); } if (String.Compare(strFunction, "modifyprice", true) == 0) { /* // 在日志中保留旧的读者记录 XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement, "oldReaderRecord", strReaderXml); DomUtil.SetAttr(node, "recPath", strOutputReaderRecPath); * */ nRet = ModifyPrice(ref readerdom, amerce_items, out strError); if (nRet == -1) goto ERROR1; if (nRet != 0) { bReaderDomChanged = true; if (this.Statis != null) this.Statis.IncreaseEntryValue( strLibraryCode, "违约金", "修改次", nRet); } else { // 如果一个事项也没有发生修改,则需要返回错误信息,以引起前端的警觉 strError = "警告:没有任何事项的价格(和注释)被修改。"; goto ERROR1; } goto SAVERECORD; } if (String.Compare(strFunction, "modifycomment", true) == 0) { /* // 在日志中保留旧的读者记录 XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement, "oldReaderRecord", strReaderXml); DomUtil.SetAttr(node, "recPath", strOutputReaderRecPath); * */ nRet = ModifyComment( ref readerdom, amerce_items, out strError); if (nRet == -1) goto ERROR1; if (nRet != 0) { bReaderDomChanged = true; if (this.Statis != null) this.Statis.IncreaseEntryValue( strLibraryCode, "违约金之注释", "修改次", nRet); } else { // 如果一个事项也没有发生修改,则需要返回错误信息,以引起前端的警觉 strError = "警告:没有任何事项的注释被修改。"; goto ERROR1; } goto SAVERECORD; } List<string> NotFoundIds = null; Ids = null; // 交违约金:在读者记录中去除所选的<overdue>元素,并且构造一批新记录准备加入违约金库 // return: // -1 error // 0 读者dom没有变化 // 1 读者dom发生了变化 nRet = DoAmerceReaderXml( strLibraryCode, ref readerdom, amerce_items, sessioninfo.UserID, strOperTimeString, out AmerceRecordXmls, out NotFoundIds, out Ids, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) bReaderDomChanged = true; // 在违约金数据库中创建若干新的违约金记录 // parameters: // AmerceRecordXmls 需要写入的新记录的数组 // CreatedNewPaths 已经创建的新记录的路径数组。可以用于Undo(删除刚刚创建的新记录) nRet = CreateAmerceRecords( // sessioninfo.Channels, channel, AmerceRecordXmls, out CreatedNewPaths, out strError); if (nRet == -1) { // undo已经写入的部分记录 if (CreatedNewPaths != null && CreatedNewPaths.Count != 0) { string strNewError = ""; nRet = DeleteAmerceRecords( sessioninfo.Channels, CreatedNewPaths, out strNewError); if (nRet == -1) { string strList = ""; for (int i = 0; i < CreatedNewPaths.Count; i++) { if (strList != "") strList += ","; strList += CreatedNewPaths[i]; } strError = "在创建新的违约金记录的过程中发生错误: " + strError + "。在Undo新创建的违约金记录的过程中,又发生错误: " + strNewError + ", 请系统管理员手工删除新创建的罚款记录: " + strList; goto ERROR1; } } goto ERROR1; } SAVERECORD: // 为写回读者、册记录做准备 // byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; #if NO RmsChannel channel = sessioninfo.Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; goto ERROR1; } #endif long lRet = 0; if (bReaderDomChanged == true) { strReaderXml = readerdom.OuterXml; lRet = channel.DoSaveTextRes(strOutputReaderRecPath, strReaderXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; // id list /* DomUtil.SetElementText(domOperLog.DocumentElement, "idList", strAmerceItemIdList); * */ WriteAmerceItemList(domOperLog, amerce_items); /* DomUtil.SetElementText(domOperLog.DocumentElement, "readerBarcode", strReaderBarcode); DomUtil.SetElementText(domOperLog.DocumentElement, "itemBarcodeList", strItemBarcodeList); */ // 仅当功能为amerce时,才把被修改的实体记录写入日志。 if (String.Compare(strFunction, "amerce", true) == 0) { Debug.Assert(AmerceRecordXmls.Count == CreatedNewPaths.Count, ""); // 写入多个重复的<amerceRecord>元素 for (int i = 0; i < AmerceRecordXmls.Count; i++) { XmlNode nodeAmerceRecord = domOperLog.CreateElement("amerceRecord"); domOperLog.DocumentElement.AppendChild(nodeAmerceRecord); nodeAmerceRecord.InnerText = AmerceRecordXmls[i]; DomUtil.SetAttr(nodeAmerceRecord, "recPath", CreatedNewPaths[i]); /* DomUtil.SetElementText(domOperLog.DocumentElement, "record", AmerceRecordXmls[i]); **/ if (this.Statis != null) this.Statis.IncreaseEntryValue( strLibraryCode, "违约金", "给付次", 1); { string strPrice = ""; // 取出违约金记录中的金额数字 nRet = GetAmerceRecordPrice(AmerceRecordXmls[i], out strPrice, out strError); if (nRet != -1) { string strPrefix = ""; string strPostfix = ""; double fValue = 0.0; // 分析价格参数 nRet = ParsePriceUnit(strPrice, out strPrefix, out fValue, out strPostfix, out strError); if (nRet != -1) { if (this.Statis != null) this.Statis.IncreaseEntryValue( strLibraryCode, "违约金", "给付元", fValue); } else { // 2012/11/15 this.WriteErrorLog("累计 违约金 给付元 [" + strPrice + "] 时出错: " + strError); } } } } // end of for } // 最新的读者记录 XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement, "readerRecord", strReaderXml); DomUtil.SetAttr(node, "recPath", strOutputReaderRecPath); string strOperTime = this.Clock.GetClock(); DomUtil.SetElementText(domOperLog.DocumentElement, "operator", sessioninfo.UserID); // 操作者 DomUtil.SetElementText(domOperLog.DocumentElement, "operTime", strOperTime); // 操作时间 nRet = this.OperLog.WriteOperLog(domOperLog, sessioninfo.ClientAddress, out strError); if (nRet == -1) { strError = "Amerce() API 写入日志时发生错误: " + strError; goto ERROR1; } } // 记忆下最近一次Amerce操作的ID和读者证条码号 if (strFunction != "rollback" && Ids != null && Ids.Count != 0) { sessioninfo.AmerceReaderBarcode = strReaderBarcode; sessioninfo.AmerceIds = Ids; } } finally { this.ReaderLocks.UnlockForWrite(strReaderBarcode); #if DEBUG_LOCK_READER this.WriteErrorLog("Amerce 结束为读者加写锁 '" + strReaderBarcode + "'"); #endif } return result; ERROR1: result.Value = -1; result.ErrorInfo = strError; result.ErrorCode = ErrorCode.SystemError; return result; }
// Undo一个已交费记录 int UndoOneAmerce(SessionInfo sessioninfo, string strReaderBarcode, string strAmercedItemId, out string strReaderXml, out string strError) { strError = ""; strReaderXml = ""; RmsChannel channel = sessioninfo.Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; goto ERROR1; } long lRet = 0; int nRet = 0; string strFrom = "ID"; string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(this.AmerceDbName + ":" + strFrom) // 2007/9/14 + "'><item><word>" + strAmercedItemId + "</word><match>" + "exact" + "</match><relation>=</relation><dataType>string</dataType><maxCount>100</maxCount></item><lang>" + "zh" + "</lang></target>"; lRet = channel.DoSearch(strQueryXml, "amerced", "", // strOuputStyle out strError); if (lRet == -1) { strError = "检索ID为 '" + strAmercedItemId + "' 的已付违约金记录出错: " + strError; return -1; } if (lRet == 0) { strError = "没有找到ID为 '" + strAmercedItemId + "' 的已付违约金记录"; return -1; } List<string> aPath = null; lRet = channel.DoGetSearchResult("amerced", 100, "zh", null, out aPath, out strError); if (lRet == -1) { strError = "检索ID为 '" + strAmercedItemId + "' 的已付违约金记录,获取浏览格式阶段出错: " + strError; return -1; } if (lRet == 0) { strError = "检索ID为 '" + strAmercedItemId + "' 的已付违约金记录,已检索命中,但是获取浏览格式没有找到"; return -1; } if (aPath.Count == 0) { strError = "检索ID为 '" + strAmercedItemId + "' 的已付违约金记录,已检索命中,但是获取浏览格式没有找到"; return -1; } if (aPath.Count > 1) { strError = "ID为 '" + strAmercedItemId + "' 的已付违约金记录检索出多条。请系统管理员及时更正此错误。"; return -1; } string strAmercedRecPath = aPath[0]; string strMetaData = ""; byte[] amerced_timestamp = null; string strOutputPath = ""; string strAmercedXml = ""; lRet = channel.GetRes(strAmercedRecPath, out strAmercedXml, out strMetaData, out amerced_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "获取已付违约金记录 '" + strAmercedRecPath + "' 时出错: " + strError; return -1; } string strOverdueString = ""; string strOutputReaderBarcode = ""; // 将违约金记录格式转换为读者记录中的<overdue>元素格式 // return: // -1 error // 0 strAmercedXml中<state>元素的值为*非*"settlemented" // 1 strAmercedXml中<state>元素的值为"settlemented" nRet = ConvertAmerceRecordToOverdueString(strAmercedXml, out strOutputReaderBarcode, out strOverdueString, out strError); if (nRet == -1) return -1; if (nRet == 1) { strError = "ID为 " + strAmercedItemId + " (路径为 '" + strOutputPath + "' ) 的违约金库记录其状态为 已结算(settlemented),不能撤回交费操作"; return -1; } // 如果strReaderBarcode参数值非空,则要检查一下检索出来的已付违约金记录是否真的属于这个读者 if (String.IsNullOrEmpty(strReaderBarcode) == false && strReaderBarcode != strOutputReaderBarcode) { strError = "ID为 '" + strAmercedItemId + "' 的已付违约金记录,并不是属于所指定的读者 '" + strReaderBarcode + "',而是属于另一读者 '" + strOutputReaderBarcode + "'"; return -1; } // 加读者记录锁 #if DEBUG_LOCK_READER this.WriteErrorLog("UndoOneAmerce 开始为读者加写锁 '" + strReaderBarcode + "'"); #endif this.ReaderLocks.LockForWrite(strReaderBarcode); try { // 读入读者记录 strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // sessioninfo.Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入读者记录时发生错误: " + strError; goto ERROR1; } string strLibraryCode = ""; // 看看读者记录所从属的读者库的馆代码,是否被当前用户管辖 if (String.IsNullOrEmpty(strOutputReaderRecPath) == false) { // 检查当前操作者是否管辖这个读者库 // 观察一个读者记录路径,看看是不是在当前用户管辖的读者库范围内? if (this.IsCurrentChangeableReaderPath(strOutputReaderRecPath, sessioninfo.LibraryCodeList, out strLibraryCode) == false) { strError = "读者记录路径 '" + strOutputReaderRecPath + "' 从属的读者库不在当前用户管辖范围内"; goto ERROR1; } } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // 准备日志DOM XmlDocument domOperLog = new XmlDocument(); domOperLog.LoadXml("<root />"); DomUtil.SetElementText(domOperLog.DocumentElement, "libraryCode", strLibraryCode); // 读者所在的馆代码 DomUtil.SetElementText(domOperLog.DocumentElement, "operation", "amerce"); bool bReaderDomChanged = false; // 修改读者记录 // 增添超期信息 if (String.IsNullOrEmpty(strOverdueString) != true) { XmlDocumentFragment fragment = readerdom.CreateDocumentFragment(); fragment.InnerXml = strOverdueString; // 看看根下面是否有overdues元素 XmlNode root = readerdom.DocumentElement.SelectSingleNode("overdues"); if (root == null) { root = readerdom.CreateElement("overdues"); readerdom.DocumentElement.AppendChild(root); } // 2008/11/11 // undo交押金 XmlNode node_added = root.AppendChild(fragment); bReaderDomChanged = true; Debug.Assert(node_added != null, ""); string strReason = DomUtil.GetAttr(node_added, "reason"); if (strReason == "押金。") { string strPrice = ""; strPrice = DomUtil.GetAttr(node_added, "newPrice"); if (String.IsNullOrEmpty(strPrice) == true) strPrice = DomUtil.GetAttr(node_added, "price"); else { Debug.Assert(strPrice.IndexOf('%') == -1, "从newPrice属性中取出来的价格字符串,岂能包含%符号"); } if (String.IsNullOrEmpty(strPrice) == false) { // 需要从<foregift>元素中减去这个价格 string strContent = DomUtil.GetElementText(readerdom.DocumentElement, "foregift"); string strNegativePrice = ""; // 将形如"-123.4+10.55-20.3"的价格字符串反转正负号 // parameters: // bSum 是否要顺便汇总? true表示要汇总 nRet = PriceUtil.NegativePrices(strPrice, false, out strNegativePrice, out strError); if (nRet == -1) { strError = "反转价格字符串 '" + strPrice + "时发生错误: " + strError; goto ERROR1; } strContent = PriceUtil.JoinPriceString(strContent, strNegativePrice); DomUtil.SetElementText(readerdom.DocumentElement, "foregift", strContent); bReaderDomChanged = true; } } } if (bReaderDomChanged == true) { byte[] output_timestamp = null; strReaderXml = readerdom.OuterXml; // 野蛮写入 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, strReaderXml, false, "content,ignorechecktimestamp", // ????? reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; int nRedoDeleteCount = 0; REDO_DELETE: // 删除已付违约金记录 lRet = channel.DoDeleteRes(strAmercedRecPath, amerced_timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch && nRedoDeleteCount < 10) { nRedoDeleteCount++; amerced_timestamp = output_timestamp; goto REDO_DELETE; } strError = "删除已付违约金记录 '" + strAmercedRecPath + "' 失败: " + strError; this.WriteErrorLog(strError); goto ERROR1; } // 具体动作 DomUtil.SetElementText(domOperLog.DocumentElement, "action", "undo"); // id list /* DomUtil.SetElementText(domOperLog.DocumentElement, "idList", strAmercedItemId); * */ AmerceItem[] amerce_items = new AmerceItem[1]; amerce_items[0] = new AmerceItem(); amerce_items[0].ID = strAmercedItemId; WriteAmerceItemList(domOperLog, amerce_items); DomUtil.SetElementText(domOperLog.DocumentElement, "readerBarcode", strReaderBarcode); /* DomUtil.SetElementText(domOperLog.DocumentElement, "amerceItemID", strAmercedItemId); */ // 删除掉的违约金记录 XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement, "amerceRecord", strAmercedXml); DomUtil.SetAttr(node, "recPath", strAmercedRecPath); // 最新的读者记录 node = DomUtil.SetElementText(domOperLog.DocumentElement, "readerRecord", strReaderXml); DomUtil.SetAttr(node, "recPath", strOutputReaderRecPath); string strOperTime = this.Clock.GetClock(); DomUtil.SetElementText(domOperLog.DocumentElement, "operator", sessioninfo.UserID); // 操作者 DomUtil.SetElementText(domOperLog.DocumentElement, "operTime", strOperTime); // 操作时间 nRet = this.OperLog.WriteOperLog(domOperLog, sessioninfo.ClientAddress, out strError); if (nRet == -1) { strError = "Amerce() API 写入日志时发生错误: " + strError; goto ERROR1; } if (this.Statis != null) this.Statis.IncreaseEntryValue(strLibraryCode, "违约金", "取消次", 1); { string strPrice = ""; // 取出违约金记录中的金额数字 nRet = GetAmerceRecordPrice(strAmercedXml, out strPrice, out strError); if (nRet != -1) { string strPrefix = ""; string strPostfix = ""; double fValue = 0.0; // 分析价格参数 nRet = ParsePriceUnit(strPrice, out strPrefix, out fValue, out strPostfix, out strError); if (nRet != -1) { if (this.Statis != null) this.Statis.IncreaseEntryValue( strLibraryCode, "违约金", "取消元", fValue); } } } } } finally { this.ReaderLocks.UnlockForWrite(strReaderBarcode); #if DEBUG_LOCK_READER this.WriteErrorLog("UndoOneAmerce 结束为读者加写锁 '" + strReaderBarcode + "'"); #endif } return 0; ERROR1: return -1; }
// UNDO违约金交纳 // return: // -1 error // 0 succeed // 1 部分成功。strError中有报错信息,failed_item中有那些没有被处理的item的列表 int UndoAmerces( SessionInfo sessioninfo, string strReaderBarcode, AmerceItem[] amerce_items, out AmerceItem[] failed_items, out string strReaderXml, out string strError) { strError = ""; strReaderXml = ""; failed_items = null; int nErrorCount = 0; List<string> OverdueStrings = new List<string>(); List<string> AmercedRecPaths = new List<string>(); // string[] ids = strAmercedItemIdList.Split(new char[] { ',' }); List<AmerceItem> failed_list = new List<AmerceItem>(); for (int i = 0; i < amerce_items.Length; i++) { AmerceItem item = amerce_items[i]; /* string strID = ids[i].Trim(); * */ if (String.IsNullOrEmpty(item.ID) == true) continue; string strTempError = ""; int nRet = UndoOneAmerce(sessioninfo, strReaderBarcode, item.ID, out strReaderXml, out strTempError); if (nRet == -1) { if (String.IsNullOrEmpty(strError) == false) strError += ";\r\n"; strError += strTempError; nErrorCount++; // return -1; failed_list.Add(item); } } // 每个ID都发生了错误 if (nErrorCount >= amerce_items.Length) return -1; // 部分发生错误 if (nErrorCount > 0) { failed_items = new AmerceItem[failed_list.Count]; failed_list.CopyTo(failed_items); strError = "操作部分成功。(共提交了 " + amerce_items.Length + " 个事项,发生错误的有 " + nErrorCount + " 个) \r\n" + strError; return 1; } return 0; }
// 交违约金:在读者记录中去除所选的<overdue>元素,并且构造一批新记录准备加入违约金库 // parameters: // strLibraryCode 读者记录从属的馆代码 // return: // -1 error // 0 读者dom没有变化 // 1 读者dom发生了变化 static int DoAmerceReaderXml( string strLibraryCode, ref XmlDocument readerdom, AmerceItem[] amerce_items, string strOperator, string strOperTimeString, out List<string> AmerceRecordXmls, out List<string> NotFoundIds, out List<string> Ids, out string strError) { strError = ""; AmerceRecordXmls = new List<string>(); NotFoundIds = new List<string>(); Ids = new List<string>(); int nRet = 0; string strReaderBarcode = DomUtil.GetElementText(readerdom.DocumentElement, "barcode"); if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "读者记录中竟然没有<barcode>元素值"; return -1; } bool bChanged = false; // 读者dom是否发生了改变 // string strNotFoundIds = ""; for (int i = 0; i < amerce_items.Length; i++) { AmerceItem item = amerce_items[i]; // string strID = ids[i].Trim(); if (String.IsNullOrEmpty(item.ID) == true) continue; XmlNode node = readerdom.DocumentElement.SelectSingleNode("overdues/overdue[@id='" + item.ID + "']"); if (node == null) { NotFoundIds.Add(item.ID); /* if (strNotFoundIds != "") strNotFoundIds += ","; strNotFoundIds += item.ID; * */ continue; } string strForegiftPrice = DomUtil.GetElementText(readerdom.DocumentElement, "foregift"); string strFinalPrice = ""; // 最终使用的价格字符串。这是从item.NewPrice和node节点的price属性中选择出来,并且经过去除宏操作的一个最后价格字符串 string strAmerceRecord = ""; // 将读者记录中的<overdue>元素和属性转换为违约金库的记录格式 nRet = ConvertOverdueStringToAmerceRecord(node, strLibraryCode, strReaderBarcode, "amerced", item.NewPrice, item.NewComment, strOperator, strOperTimeString, strForegiftPrice, out strFinalPrice, out strAmerceRecord, out strError); if (nRet == -1) return -1; AmerceRecordXmls.Add(strAmerceRecord); Ids.Add(item.ID); // 如果是押金,需要增/减<foregift>元素内的价格值。交费为增,退费为减。不过正负号已经含在价格字符串中,可以都理解为交费 string strReason = ""; strReason = DomUtil.GetAttr(node, "reason"); // 2008/11/11 if (strReason == "押金。") { string strNewPrice = ""; /* string strOldPrice = DomUtil.GetElementText(readerdom.DocumentElement, "foregift"); if (strOldPrice.IndexOf('%') != -1) { strError = "来自读者记录<foregift>元素的价格字符串 '" + strOldPrice + "' 格式错误:价格字符串中不允许出现%符号"; return -1; } string strPrice = ""; if (String.IsNullOrEmpty(item.NewPrice) == true) strPrice = DomUtil.GetAttr(node, "price"); else strPrice = item.NewPrice; // 看看价格字符串是否为宏? if (strPrice == "%return_foregift_price%") { // 将形如"-123.4+10.55-20.3"的价格字符串反转正负号 // parameters: // bSum 是否要顺便汇总? true表示要汇总 nRet = PriceUtil.NegativePrices(strOldPrice, true, out strPrice, out strError); if (nRet == -1) { strError = "反转(来自读者记录中的<foregift>元素的)价格字符串 '" + strOldPrice + "' 时出错: " + strError; return -1; } } if (strPrice.IndexOf('%') != -1) { strError = "价格字符串 '" + strPrice + "' 格式错误:除了使用宏%return_foregift_price%以外,价格字符串中不允许出现%符号"; return -1; } if (String.IsNullOrEmpty(strOldPrice) == false) { strNewPrice = PriceUtil.JoinPriceString(strOldPrice, strPrice); } else { strNewPrice = strPrice; } * */ if (String.IsNullOrEmpty(strForegiftPrice) == false) { strNewPrice = PriceUtil.JoinPriceString(strForegiftPrice, strFinalPrice); } else { strNewPrice = strFinalPrice; } DomUtil.SetElementText(readerdom.DocumentElement, "foregift", strNewPrice); // 是否顺便写入最近一次的交费时间? bChanged = true; } // 在读者记录中删除这个节点 node.ParentNode.RemoveChild(node); bChanged = true; } /* if (strNotFoundIds != "") { strError = "下列id没有相匹配的<overdue>元素" + strNotFoundIds; return -1; }*/ if (NotFoundIds.Count > 0) { strError = "下列id没有相匹配的<overdue>元素: " + StringUtil.MakePathList(NotFoundIds); return -1; } if (bChanged == true) return 1; return 0; }
// 在日志DOM中写入违约金事项信息 static void WriteAmerceItemList(XmlDocument domOperLog, AmerceItem[] amerce_items) { XmlNode root = domOperLog.CreateElement("amerceItems"); domOperLog.DocumentElement.AppendChild(root); for (int i = 0; i < amerce_items.Length; i++) { AmerceItem item = amerce_items[i]; XmlNode node = domOperLog.CreateElement("amerceItem"); root.AppendChild(node); DomUtil.SetAttr(node, "id", item.ID); if (String.IsNullOrEmpty(item.NewPrice) == false) DomUtil.SetAttr(node, "newPrice", item.NewPrice); // 2007/4/17 if (String.IsNullOrEmpty(item.NewComment) == false) DomUtil.SetAttr(node, "newComment", item.NewComment); } /* // id list DomUtil.SetElementText(domOperLog.DocumentElement, "idList", strAmerceItemIdList); */ }
// 从日志DOM中读出违约金事项信息 public static AmerceItem[] ReadAmerceItemList(XmlDocument domOperLog) { XmlNodeList nodes = domOperLog.DocumentElement.SelectNodes("amerceItems/amerceItem"); AmerceItem[] results = new AmerceItem[nodes.Count]; for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strID = DomUtil.GetAttr(node, "id"); string strNewPrice = DomUtil.GetAttr(node, "newPrice"); string strComment = DomUtil.GetAttr(node, "newComment"); results[i] = new AmerceItem(); results[i].ID = strID; results[i].NewPrice = strNewPrice; results[i].NewComment = strComment; // 2007/4/17 } return results; }
// 2008/6/19 // 根据AmerceItem数组,修改readerdom中的<amerce>元素中的comment属性。 // 为功能"modifycomment"服务。 int ModifyComment( ref XmlDocument readerdom, AmerceItem[] amerce_items, out string strError) { strError = ""; int nChangedCount = 0; for (int i = 0; i < amerce_items.Length; i++) { AmerceItem item = amerce_items[i]; // 不能同时修改价格。 if (String.IsNullOrEmpty(item.NewPrice) == false) { strError = "不能用modifycomment子功能来修改价格,请改用modifyprice子功能"; return -1; } /* // 遇到NewComment域值为空、并且为追加的,直接跳过 if (String.IsNullOrEmpty(item.NewComment) == true && strFunction == "appendcomment") { continue; }*/ // 通过id值在读者记录中找到对应的<overdue>元素 XmlNode nodeOverdue = readerdom.DocumentElement.SelectSingleNode("overdues/overdue[@id='" + item.ID + "']"); if (nodeOverdue == null) { strError = "ID为 '" + item.ID + "' 的<overdues/overdue>元素没有找到..."; return -1; } { string strExistComment = DomUtil.GetAttr(nodeOverdue, "comment"); // 增补或修改注释 string strNewComment = item.NewComment; // 处理追加标志 bool bAppend = true; if (string.IsNullOrEmpty(strNewComment) == false && strNewComment[0] == '<') { bAppend = false; strNewComment = strNewComment.Substring(1); } else if (string.IsNullOrEmpty(strNewComment) == false && strNewComment[0] == '>') { bAppend = true; strNewComment = strNewComment.Substring(1); } if (String.IsNullOrEmpty(strNewComment) == false && bAppend == true) { string strText = ""; if (String.IsNullOrEmpty(strExistComment) == false) strText += strExistComment; if (String.IsNullOrEmpty(strNewComment) == false) { if (String.IsNullOrEmpty(strText) == false) strText += ";"; strText += strNewComment; } DomUtil.SetAttr(nodeOverdue, "comment", strText); nChangedCount++; } else if (bAppend == false) { DomUtil.SetAttr(nodeOverdue, "comment", strNewComment); nChangedCount++; // BUG!!! 2011/12/1前少了这句话 } } } return nChangedCount; }
// 根据AmerceItem数组,修改readerdom中的<amerce>元素中的价格price属性。 // 为功能"modifyprice"服务。 int ModifyPrice(ref XmlDocument readerdom, AmerceItem[] amerce_items, out string strError) { strError = ""; int nChangedCount = 0; for (int i = 0; i < amerce_items.Length; i++) { AmerceItem item = amerce_items[i]; // 遇到NewPrice域值为空的,直接跳过。 // 这说明,不接受修改价格为完全空的字符串。 if (String.IsNullOrEmpty(item.NewPrice) == true) { if (String.IsNullOrEmpty(item.NewComment) == false) { strError = "不能用modifyprice子功能来单独修改注释(而不修改价格),请改用appendcomment和modifycomment子功能"; return -1; } continue; } // 通过id值在读者记录中找到对应的<overdue>元素 XmlNode nodeOverdue = readerdom.DocumentElement.SelectSingleNode("overdues/overdue[@id='" + item.ID + "']"); if (nodeOverdue == null) { strError = "ID为 '" + item.ID + "' 的<overdues/overdue>元素没有找到..."; return -1; } string strOldPrice = DomUtil.GetAttr(nodeOverdue, "price"); if (strOldPrice != item.NewPrice) { // 修改price属性 DomUtil.SetAttr(nodeOverdue, "price", item.NewPrice); nChangedCount++; // 增补注释 string strNewComment = item.NewComment; string strExistComment = DomUtil.GetAttr(nodeOverdue, "comment"); // 处理追加标志 bool bAppend = true; if (string.IsNullOrEmpty(strNewComment) == false && strNewComment[0] == '<') { bAppend = false; strNewComment = strNewComment.Substring(1); } else if (string.IsNullOrEmpty(strNewComment) == false && strNewComment[0] == '>') { bAppend = true; strNewComment = strNewComment.Substring(1); } if (String.IsNullOrEmpty(strNewComment) == false && bAppend == true) { string strText = ""; if (String.IsNullOrEmpty(strExistComment) == false) strText += strExistComment; if (String.IsNullOrEmpty(strNewComment) == false) { if (String.IsNullOrEmpty(strText) == false) strText += ";"; strText += strNewComment; } DomUtil.SetAttr(nodeOverdue, "comment", strText); } else if (bAppend == false) { DomUtil.SetAttr(nodeOverdue, "comment", strNewComment); } } } return nChangedCount; }