BillsMeasureDm.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. unit BillsMeasureDm;
  2. interface
  3. uses
  4. BillsDm, BillsTree, FormulaCalc, sdIDTree, StageDm,
  5. SysUtils, Classes, sdDB;
  6. type
  7. TBillsMeasureData = class(TDataModule)
  8. sdvBillsMeasure: TsdDataView;
  9. procedure sdvBillsMeasureAfterOpen(Sender: TObject);
  10. procedure sdvBillsMeasureAfterAddRecord(ARecord: TsdDataRecord);
  11. procedure sdvBillsMeasureGetText(var Text: String;
  12. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  13. DisplayText: Boolean);
  14. procedure sdvBillsMeasureSetText(var Text: String;
  15. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  16. var Allow: Boolean);
  17. procedure sdvBillsMeasureNeedLookupRecord(ARecord: TsdDataRecord;
  18. AColumn: TsdViewColumn; ANewText: String);
  19. procedure sdvBillsMeasureAfterClose(Sender: TObject);
  20. procedure sdvBillsMeasureAfterValueChanged(AValue: TsdValue);
  21. procedure sdvBillsMeasureCurrentChanged(ARecord: TsdDataRecord);
  22. private
  23. FProjectData: TObject;
  24. FBillsData: TBillsData;
  25. FBillsMeasureTree: TBillsIDTree;
  26. FFormulaCalc: TFormulaCalc;
  27. FShowParentData: Boolean;
  28. FOnRecChange: TRecChangeEvent;
  29. function OnGetCardinalNum(const ACardinalNum: string): Double;
  30. procedure CalcAddCompleteRate(ANode: TsdIDTreeNode);
  31. procedure CalcAddDgnPrice(ANode: TsdIDTreeNode);
  32. procedure UpdateRecordGather(ANode: TsdIDTreeNode; AQuantity, ATotalPrice: Double);
  33. function SelectAndUpdateBGL(ABillsID: Integer; ARec: TsdDataRecord;
  34. ANewValue: Double; const AType: string): Boolean;
  35. function GetStageData: TStageData;
  36. procedure SetOnRecChange(const Value: TRecChangeEvent);
  37. public
  38. constructor Create(AProjectData: TObject);
  39. destructor Destroy; override;
  40. procedure Open;
  41. procedure Close;
  42. procedure ReConnectTree;
  43. procedure CalculateAll;
  44. procedure ResetPhaseStageLink;
  45. procedure ResetTreeNodeStageRec;
  46. procedure ExpandNodeTo(ALevel: Integer);
  47. procedure ExpandXmjNode;
  48. procedure ExpandCurPhase;
  49. function GatherRelaBGL(ANode: TsdIDTreeNode): string;
  50. // 计算 修改各期原报审核数据时,需对累计数据做增量
  51. procedure UpdateRecordDeal(ABillsID: Integer; AQuantity, ATotalPrice: Double);
  52. procedure UpdateRecordQc(ABillsID: Integer; AQuantity, ATotalPrice: Double);
  53. procedure UpdateRecordPc(ABillsID: Integer; AQuantity, ATotalPrice: Double);
  54. procedure UpdateBGLInfo(ABillsID: Integer; ARec: TsdDataRecord; const AType: string);
  55. property ProjectData: TObject read FProjectData;
  56. property BillsData: TBillsData read FBillsData;
  57. property BillsMeasureTree: TBillsIDTree read FBillsMeasureTree;
  58. property StageData: TStageData read GetStageData;
  59. property ShowParentData: Boolean read FShowParentData write FShowParentData;
  60. property OnRecChange: TRecChangeEvent read FOnRecChange write SetOnRecChange;
  61. end;
  62. implementation
  63. uses
  64. ProjectData, PhaseData, Math, ZhAPI, BillsCommand, BGLSelectFrm,
  65. BGLDm, UtilMethods, mDataRecord;
  66. {$R *.dfm}
  67. { TBillsMeasureData }
  68. constructor TBillsMeasureData.Create(AProjectData: TObject);
  69. begin
  70. inherited Create(nil);
  71. FProjectData := AProjectData;
  72. FBillsData := TProjectData(FProjectData).BillsData;
  73. FBillsMeasureTree := TBillsIDTree.Create;
  74. FBillsMeasureTree.KeyFieldName := 'ID';
  75. FBillsMeasureTree.ParentFieldName := 'ParentID';
  76. FBillsMeasureTree.NextSiblingFieldName := 'NextSiblingID';
  77. FBillsMeasureTree.AutoCreateKeyID := True;
  78. FBillsMeasureTree.AutoExpand := True;
  79. FBillsMeasureTree.DataView := sdvBillsMeasure;
  80. FBillsMeasureTree.SeedID := Max(FBillsMeasureTree.SeedID, 100);
  81. FBillsMeasureTree.Link(TProjectData(FProjectData).BillsCompileData.BillsCompileTree, True);
  82. FFormulaCalc := TFormulaCalc.Create(FBillsMeasureTree);
  83. FFormulaCalc.OnGetValue := OnGetCardinalNum;
  84. end;
  85. destructor TBillsMeasureData.Destroy;
  86. begin
  87. FFormulaCalc.Free;
  88. FBillsMeasureTree.Free;
  89. inherited;
  90. end;
  91. procedure TBillsMeasureData.Open;
  92. begin
  93. sdvBillsMeasure.DataSet := TProjectData(FProjectData).BillsData.sddBills;
  94. sdvBillsMeasure.Open;
  95. end;
  96. procedure TBillsMeasureData.ReConnectTree;
  97. begin
  98. FBillsMeasureTree.DataView := nil;
  99. FBillsMeasureTree.DataView := sdvBillsMeasure;
  100. FBillsMeasureTree.Link(TProjectData(FProjectData).BillsCompileData.BillsCompileTree, True);
  101. end;
  102. procedure TBillsMeasureData.ResetPhaseStageLink;
  103. begin
  104. with TProjectData(FProjectData).PhaseData do
  105. begin
  106. sdvBillsMeasure.Columns.FindColumn('CurDealQuantity').LookupDataSet := StageData.sddStage;
  107. sdvBillsMeasure.Columns.FindColumn('CurDealTotalPrice').LookupDataSet := StageData.sddStage;
  108. sdvBillsMeasure.Columns.FindColumn('CurQcQuantity').LookupDataSet := StageData.sddStage;
  109. sdvBillsMeasure.Columns.FindColumn('CurQcTotalPrice').LookupDataSet := StageData.sddStage;
  110. sdvBillsMeasure.Columns.FindColumn('CurQcBGLCode').LookupDataSet := StageData.sddStage;
  111. sdvBillsMeasure.Columns.FindColumn('CurPcQuantity').LookupDataSet := StageData.sddStage;
  112. sdvBillsMeasure.Columns.FindColumn('CurPcTotalPrice').LookupDataSet := StageData.sddStage;
  113. sdvBillsMeasure.Columns.FindColumn('CurPcBGLCode').LookupDataSet := StageData.sddStage;
  114. sdvBillsMeasure.Columns.FindColumn('CurGatherQuantity').LookupDataSet := StageData.sddStage;
  115. sdvBillsMeasure.Columns.FindColumn('CurGatherTotalPrice').LookupDataSet := StageData.sddStage;
  116. sdvBillsMeasure.Columns.FindColumn('EndDealQuantity').LookupDataSet := StageData.sddStage;
  117. sdvBillsMeasure.Columns.FindColumn('EndDealTotalPrice').LookupDataSet := StageData.sddStage;
  118. sdvBillsMeasure.Columns.FindColumn('EndQcQuantity').LookupDataSet := StageData.sddStage;
  119. sdvBillsMeasure.Columns.FindColumn('EndQcTotalPrice').LookupDataSet := StageData.sddStage;
  120. sdvBillsMeasure.Columns.FindColumn('EndPcQuantity').LookupDataSet := StageData.sddStage;
  121. sdvBillsMeasure.Columns.FindColumn('EndPcTotalPrice').LookupDataSet := StageData.sddStage;
  122. sdvBillsMeasure.Columns.FindColumn('EndGatherQuantity').LookupDataSet := StageData.sddStage;
  123. sdvBillsMeasure.Columns.FindColumn('EndGatherTotalPrice').LookupDataSet := StageData.sddStage;
  124. end;
  125. end;
  126. procedure TBillsMeasureData.sdvBillsMeasureAfterOpen(Sender: TObject);
  127. begin
  128. FBillsMeasureTree.Active := True;
  129. end;
  130. procedure TBillsMeasureData.sdvBillsMeasureAfterAddRecord(
  131. ARecord: TsdDataRecord);
  132. begin
  133. ARecord.ValueByName('IsMeasureAdd').AsBoolean := True;
  134. end;
  135. procedure TBillsMeasureData.sdvBillsMeasureGetText(var Text: String;
  136. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  137. DisplayText: Boolean);
  138. function GetQuantityValueOrFormula(const AQtyType: string): string;
  139. begin
  140. with AValue.Owner do
  141. begin
  142. if ValueByName(AQtyType + 'Flag').AsInteger = 1 then
  143. Result := ValueByName(AQtyType + 'Formula').AsString
  144. else
  145. Result := Text;
  146. end;
  147. end;
  148. function GetTotalPriceValueOrFormula(const AQtyType: string): string;
  149. begin
  150. with AValue.Owner do
  151. begin
  152. if ValueByName(AQtyType + 'Formula').AsString <> '' then
  153. Result := ValueByName(AQtyType + 'Formula').AsString
  154. else
  155. Result := Text;
  156. end;
  157. end;
  158. procedure GetDisplayText(var AText: string; AValue: TsdValue;
  159. AColumn: TsdViewColumn);
  160. var
  161. stnNode: TsdIDTreeNode;
  162. begin
  163. if (Pos('TotalPrice', AColumn.FieldName) > 0) or
  164. (Pos('Quantity', AColumn.FieldName) > 0) or
  165. (Pos('Price', AColumn.FieldName) > 0) then
  166. begin
  167. if AValue.AsFloat = 0 then
  168. Text := '';
  169. end;
  170. if SameText('Quantity', AColumn.FieldName) or
  171. SameText('Price', AColumn.FieldName) or
  172. SameText('NewPrice', AColumn.FieldName) or
  173. SameText('AddGatherQuantity', AColumn.FieldName) then
  174. begin
  175. stnNode := BillsMeasureTree.FindNode(AValue.Owner.ValueByName('ID').AsInteger);
  176. if stnNode.HasChildren then
  177. Text := '';
  178. end;
  179. // 所有本期数据,当节点为父节点时,不显示值(实际上需要计算其中的金额值,但又不能显示)
  180. // 有病。每天都在变。
  181. if not ShowParentData and (Pos('Cur', AColumn.FieldName) > 0) and (Pos('Gather', AColumn.FieldName) = 0) then
  182. begin
  183. stnNode := BillsMeasureTree.FindNode(AValue.Owner.ValueByName('BillsID').AsInteger);
  184. if stnNode.HasChildren then
  185. Text := '';
  186. end;
  187. end;
  188. procedure GetEditText(var AText: string; AValue: TsdValue;
  189. AColumn: TsdViewColumn);
  190. begin
  191. if SameText(AColumn.FieldName, 'Quantity') then
  192. Text := GetQuantityValueOrFormula('Qty')
  193. else if SameText(AColumn.FieldName, 'CurDealQuantity') then
  194. Text := GetQuantityValueOrFormula('Deal')
  195. else if SameText(AColumn.FieldName, 'CurQcQuantity') then
  196. Text := GetQuantityValueOrFormula('Qc')
  197. else if SameText(AColumn.FieldName, 'CurPcQuantity') then
  198. Text := GetQuantityValueOrFormula('Pc')
  199. else if SameText(AColumn.FieldName, 'CurDealTotalPrice') then
  200. Text := GetTotalPriceValueOrFormula('Deal')
  201. else if SameText(AColumn.FieldName, 'CurQcTotalPrice') then
  202. Text := GetTotalPriceValueOrFormula('Qc')
  203. else if SameText(AColumn.FieldName, 'CurPcTotalPrice') then
  204. Text := GetTotalPriceValueOrFormula('Pc');
  205. end;
  206. var
  207. fPercent: Double;
  208. begin
  209. if not Assigned(AValue) then Exit;
  210. if DisplayText then
  211. GetDisplayText(Text, AValue, AColumn)
  212. else
  213. GetEditText(Text, AValue, AColumn);
  214. end;
  215. procedure TBillsMeasureData.sdvBillsMeasureSetText(var Text: String;
  216. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  217. var Allow: Boolean);
  218. function GetBillsID: Integer;
  219. begin
  220. if Pos('Cur', AColumn.FieldName) = 1 then
  221. Result := AValue.Owner.ValueByName('BillsID').AsInteger
  222. else
  223. Result := ARecord.ValueByName('ID').AsInteger;
  224. end;
  225. procedure CheckLockedData;
  226. begin
  227. if SameText(AColumn.FieldName, 'Code') or
  228. SameText(AColumn.FieldName, 'B_Code') or
  229. SameText(AColumn.FieldName, 'Name') or
  230. SameText(AColumn.FieldName, 'Units') or
  231. SameText(AColumn.FieldName, 'Price') then
  232. if ARecord.ValueByName('LockedInfo').AsBoolean then
  233. DataSetErrorMessage(Allow, '清单信息已被锁定,不允许修改编号、名称、单位、清单单价!');
  234. if not Allow then Exit;
  235. if SameText(AColumn.FieldName, 'NewPrice') then
  236. if ARecord.ValueByName('LockedNewPrice').AsBoolean then
  237. DataSetErrorMessage(Allow, '变更单价已被锁定,不允许修改!');
  238. end;
  239. procedure CheckNodeWritable;
  240. var
  241. vNode: TBillsIDTreeNode;
  242. iCreatePhase: Integer;
  243. begin
  244. vNode := TBillsIDTreeNode(BillsMeasureTree.FindNode(GetBillsID));
  245. iCreatePhase := vNode.Rec.ValueByName('CreatePhaseID').AsInteger;
  246. if SameText('B_Code', AColumn.FieldName) or
  247. SameText('Name', AColumn.FieldName) or
  248. SameText('Units', AColumn.FieldName) then
  249. if vNode.Rec.ValueByName('AddQcQuantity').AsFloat <> 0 then
  250. DataSetErrorMessage(Allow, '该清单已进行过变更,不可修改清单编号、名称、单位!');
  251. if not Allow then Exit;
  252. if SameText('Price', AColumn.FieldName) then
  253. if vNode.Rec.ValueByName('AddGatherTotalPrice').AsFloat <> 0 then
  254. DataSetErrorMessage(Allow, '该清单已经计量,不可修改清单单价!');
  255. if not Allow then Exit;
  256. if SameText('NewPrice', AColumn.FieldName) then
  257. if vNode.Rec.ValueByName('AddPcTotalPrice').AsFloat <> 0 then
  258. DataSetErrorMessage(Allow, '该清单已经计量,不可修改清单变更单价!');
  259. if not Allow then Exit;
  260. if vNode.HasChildren then
  261. begin
  262. if Text = '' then
  263. Exit
  264. else if ((Pos('Quantity', AColumn.FieldName) > 0) and (Pos('Dgn', AColumn.FieldName) <=0)) or
  265. (Pos('TotalPrice', AColumn.FieldName) > 0) then
  266. DataSetErrorMessage(Allow, '该清单有子计算项,不能直接修改!')
  267. else if (Pos('Price', AColumn.FieldName) > 0) then
  268. DataSetErrorMessage(Allow, '仅最底层清单可输入单价!');
  269. end
  270. else
  271. begin
  272. // 目前仅允许本期合同计量,可直接输入金额
  273. if SameText('CurDealTotalPrice', AColumn.FieldName) then
  274. begin
  275. if not vNode.TotalPriceEnable then
  276. DataSetErrorMessage(Allow, '该清单不可直接输入金额,如需直接输入金额,请先清空所有数量、单价!');
  277. end
  278. else if SameText('CurDealQuantity', AColumn.FieldName) or
  279. SameText('CurQcQuantity', AColumn.FieldName) or
  280. SameText('CurPcQuantity', AColumn.FieldName) or
  281. SameText('Price', AColumn.FieldName) then
  282. begin
  283. if not vNode.CountPriceEnable then
  284. DataSetErrorMessage(Allow, '该清单不可输入数量单价,如需使用数量×单价计算,请先清空所有直接输入的金额!');
  285. end;
  286. end;
  287. if not Allow then Exit;
  288. // 变更清单允许填写本期合同计量,按超计论
  289. {if vNode.Rec.ValueByName('IsMeasureAdd').AsBoolean and (iCreatePhase > 0) and
  290. (SameText('CurDealQuantity', AColumn.FieldName) or
  291. SameText('CurDealTotalPrice', AColumn.FieldName)) then
  292. DataSetErrorMessage(Allow, Format('该清单为第%d期新增清单,不可填写本期合同计量数据!', [iCreatePhase]));}
  293. end;
  294. procedure SetQuantity(const AField: string);
  295. var
  296. vNode: TBillsIDTreeNode;
  297. begin
  298. // 变更应选择变更令
  299. if SameText(AField , 'Qc') or SameText(AField , 'Pc') then
  300. Allow := SelectAndUpdateBGL(GetBillsID, AValue.Owner, StrToFloatDef(Text, 0), AField);
  301. if not Allow then Exit;
  302. if CheckStringNull(Text) or CheckNumeric(Text) then
  303. begin
  304. AValue.Owner.ValueByName(AField + 'Flag').AsInteger := 0;
  305. AValue.Owner.ValueByName(AField + 'Formula').AsString := '';
  306. Text := FloatToStr(QuantityRoundTo(StrToFloatDef(Text, 0)));
  307. end
  308. else
  309. begin
  310. AValue.Owner.ValueByName(AField + 'Flag').AsInteger := 1;
  311. AValue.Owner.ValueByName(AField + 'Formula').AsString := Text;
  312. Text := FloatToStr(QuantityRoundTo(EvaluateExprs(Text)));
  313. end;
  314. vNode := TBillsIDTreeNode(BillsMeasureTree.FindNode(GetBillsID));
  315. if vNode.Rec.CalcType.AsInteger <> 0 then
  316. vNode.Rec.CalcType.AsInteger := 0;
  317. end;
  318. procedure SetTotalPrice(const AField: string);
  319. var
  320. vNode: TBillsIDTreeNode;
  321. begin
  322. // 变更应选择变更令
  323. if SameText(AField , 'Qc') or SameText(AField , 'Pc') then
  324. Allow := SelectAndUpdateBGL(GetBillsID, AValue.Owner, StrToFloatDef(Text, 0), AField);
  325. if not Allow then Exit;
  326. AValue.Owner.ValueByName(AField + 'Flag').AsInteger := 2;
  327. AValue.Owner.ValueByName(AField + 'Quantity').AsString := '';
  328. if CheckStringNull(Text) or CheckNumeric(Text) then
  329. begin
  330. AValue.Owner.ValueByName(AField + 'Formula').AsString := '';
  331. Text := FloatToStr(TotalPriceRoundTo(StrToFloatDef(Text, 0)));
  332. end
  333. else
  334. begin
  335. AValue.Owner.ValueByName(AField + 'Formula').AsString := Text;
  336. Text := FloatToStr(TotalPriceRoundTo(EvaluateExprs(Text)));
  337. end;
  338. vNode := TBillsIDTreeNode(BillsMeasureTree.FindNode(GetBillsID));
  339. if vNode.Rec.CalcType.AsInteger <> 1 then
  340. vNode.Rec.CalcType.AsInteger := 1;
  341. end;
  342. procedure DoCurChanged;
  343. begin
  344. if SameText(AColumn.FieldName, 'CurDealQuantity') then
  345. SetQuantity('Deal')
  346. else if SameText(AColumn.FieldName, 'CurQcQuantity') then
  347. SetQuantity('Qc')
  348. else if SameText(AColumn.FieldName, 'CurPcQuantity') then
  349. SetQuantity('Pc')
  350. else if SameText(AColumn.FieldName, 'CurDealTotalPrice') then
  351. SetTotalPrice('Deal')
  352. else if SameText(AColumn.FieldName, 'CurQcTotalPrice') then
  353. SetTotalPrice('Qc')
  354. else if SameText(AColumn.FieldName, 'CurPcTotalPrice') then
  355. SetTotalPrice('Pc')
  356. else if (Pos('DgnQuantity', AColumn.FieldName) > 0) or
  357. SameText(AColumn.FieldName, 'Quantity') then
  358. Text := FloatToStr(QuantityRoundTo(StrToFloatDef(Text, 0)))
  359. else if SameText(AColumn.FieldName, 'NewPrice') or
  360. SameText(AColumn.FieldName, 'Price') then
  361. Text := FloatToStr(PriceRoundTo(StrToFloatDef(Text, 0)));
  362. end;
  363. function CheckValidData: Boolean;
  364. begin
  365. Result := (AValue.AsString <> Text);
  366. if (Pos('Quantity', AColumn.FieldName) > 0) or
  367. (Pos('Price', AColumn.FieldName) > 0) then
  368. begin
  369. if (AValue.AsFloat = 0) and (Text = '') then
  370. Result := False;
  371. end;
  372. end;
  373. begin
  374. if not Assigned(AValue) then Exit;
  375. // 修改后数据与原数据相同则不提交
  376. if not CheckValidData then
  377. Allow := False;
  378. if not Allow then Exit;
  379. if (AValue.AsString = Text) or ((AValue.AsFloat = 0) and (Text = '')) then Exit;
  380. CheckLockedData;
  381. if not Allow then Exit;
  382. CheckNodeWritable;
  383. if not Allow then Exit;
  384. Text := Trim(Text);
  385. if Pos('=', Text) = 1 then
  386. Text := Copy(Text, 2, Length(Text) - 1);
  387. DoCurChanged;
  388. end;
  389. procedure TBillsMeasureData.sdvBillsMeasureNeedLookupRecord(
  390. ARecord: TsdDataRecord; AColumn: TsdViewColumn; ANewText: String);
  391. function CheckNeedAddPhaseRecord(ANode: TBillsIDTreeNode): Boolean;
  392. begin
  393. Result := SameText(AColumn.FieldName, 'CurDealQuantity') or
  394. SameText(AColumn.FieldName, 'CurQcQuantity') or
  395. SameText(AColumn.FieldName, 'CurPcQuantity') or
  396. SameText(AColumn.FieldName, 'CurDealTotalPrice') or
  397. SameText(AColumn.FieldName, 'CurQcTotalPrice') or
  398. SameText(AColumn.FieldName, 'CurPcTotalPrice');
  399. Result := Result and not ANode.HasChildren;
  400. Result := Result and not Assigned(ANode.StageRec);
  401. end;
  402. function HasCardinalNum(AFormula: string): Boolean;
  403. var
  404. iCharIndex: Integer;
  405. begin
  406. Result := False;
  407. iCharIndex := 1;
  408. while ((iCharIndex <= Length(AFormula)) and not Result) do
  409. begin
  410. if AFormula[iCharIndex] in ['A'..'D', 'a'..'d'] then
  411. Result := True;
  412. Inc(iCharIndex);
  413. end;
  414. end;
  415. procedure SetQuantityRec(APhaseRec: TsdDataRecord; const AType: string);
  416. var
  417. bAllow: Boolean;
  418. begin
  419. bAllow := True;
  420. // 变更应选择变更令
  421. if SameText(AType , 'Qc') or SameText(AType , 'Pc') then
  422. bAllow := SelectAndUpdateBGL(ARecord.ValueByName('ID').AsInteger,
  423. APhaseRec, StrToFloatDef(ANewText, 0), AType);
  424. if bAllow then
  425. begin
  426. if CheckNumeric(ANewText) then
  427. APhaseRec.ValueByName(AType + 'Quantity').AsFloat := QuantityRoundTo(StrToFloatDef(ANewText, 0))
  428. else
  429. begin
  430. APhaseRec.ValueByName(AType + 'Flag').AsInteger := 1;
  431. APhaseRec.ValueByName(AType + 'Quantity').AsFloat := QuantityRoundTo(EvaluateExprs(ANewText));
  432. APhaseRec.ValueByName(AType + 'Formula').AsString := ANewText;
  433. end;
  434. end;
  435. end;
  436. procedure SetTotalPriceRec(APhaseRec: TsdDataRecord; const AType: string);
  437. begin
  438. APhaseRec.ValueByName(AType + 'Flag').AsInteger := 2;
  439. if CheckNumeric(ANewText) then
  440. APhaseRec.ValueByName(AType + 'TotalPrice').AsFloat := TotalPriceRoundTo(StrToFloatDef(ANewText, 0))
  441. else
  442. begin
  443. APhaseRec.ValueByName(AType + 'TotalPrice').AsFloat := TotalPriceRoundTo(EvaluateExprs(ANewText));
  444. APhaseRec.ValueByName(AType + 'Formula').AsString := ANewText;
  445. end;
  446. end;
  447. procedure SetNewRecValue(APhaseRec: TsdDataRecord);
  448. begin
  449. if SameText(AColumn.FieldName, 'CurDealQuantity') then
  450. SetQuantityRec(APhaseRec, 'Deal')
  451. else if SameText(AColumn.FieldName, 'CurQcQuantity') then
  452. SetQuantityRec(APhaseRec, 'Qc')
  453. else if SameText(AColumn.FieldName, 'CurPcQuantity') then
  454. SetQuantityRec(APhaseRec, 'Pc')
  455. else if SameText(AColumn.FieldName, 'CurDealTotalPrice') then
  456. SetTotalPriceRec(APhaseRec, 'Deal')
  457. else if SameText(AColumn.FieldName, 'CurQcTotalPrice') then
  458. SetTotalPriceRec(APhaseRec, 'Qc')
  459. else if SameText(AColumn.FieldName, 'CurPcTotalPrice') then
  460. SetTotalPriceRec(APhaseRec, 'Pc');
  461. end;
  462. function CheckNodeWritable(ANode: TBillsIDTreeNode): Boolean;
  463. var
  464. iCreatePhase: Integer;
  465. begin
  466. Result := True;
  467. if ANode.HasChildren then
  468. begin
  469. if ANewText = '' then
  470. Result := False
  471. else
  472. DataSetErrorMessage(Result, '该清单有子计算项,不能直接修改!');
  473. end
  474. else
  475. begin
  476. // 目前仅允许本期合同计量,可直接输入金额
  477. if SameText('CurDealTotalPrice', AColumn.FieldName) then
  478. begin
  479. if not ANode.TotalPriceEnable then
  480. DataSetErrorMessage(Result, '该清单不可直接输入金额,如需直接输入金额,请先清空所有数量、单价!');
  481. end
  482. else if SameText('CurDealQuantity', AColumn.FieldName) or
  483. SameText('CurQcQuantity', AColumn.FieldName) or
  484. SameText('CurPcQuantity', AColumn.FieldName) then
  485. begin
  486. if not ANode.CountPriceEnable then
  487. DataSetErrorMessage(Result, '该清单不可输入数量单价,如需使用数量×单价计算,请先清空所有直接输入的金额!');
  488. end;
  489. end;
  490. // 变更清单允许填写本期合同计量,按超计论
  491. {iCreatePhase := ANode.Rec.ValueByName('CreatePhaseID').AsInteger;
  492. if ANode.Rec.ValueByName('IsMeasureAdd').AsBoolean and (iCreatePhase > 0) and
  493. (SameText('CurDealQuantity', AColumn.FieldName) or
  494. SameText('CurDealTotalPrice', AColumn.FieldName)) then
  495. begin
  496. ErrorMessage(Format('该清单为第%d期新增清单,不可填写本期合同计量数据!', [iCreatePhase]));
  497. Exit;
  498. end; }
  499. end;
  500. var
  501. NewRec: TStageRecord;
  502. vNode: TBillsIDTreeNode;
  503. begin
  504. vNode := TBillsIDTreeNode(BillsMeasureTree.FindNode(ARecord.ValueByName('ID').AsInteger));
  505. if not CheckNodeWritable(vNode) then
  506. Exit;
  507. if CheckNeedAddPhaseRecord(vNode) then
  508. begin
  509. if Pos('Quantity', AColumn.FieldName) > 0 then
  510. if HasCardinalNum(ANewText) then
  511. raise Exception.Create('数量列公式不可输入参数');
  512. NewRec := StageData.AddStageRecord(ARecord.ValueByName('ID').AsInteger);
  513. SetNewRecValue(NewRec);
  514. vNode.StageRec := NewRec;
  515. end;
  516. end;
  517. procedure TBillsMeasureData.sdvBillsMeasureAfterClose(Sender: TObject);
  518. begin
  519. FBillsMeasureTree.Active := False;
  520. end;
  521. function TBillsMeasureData.OnGetCardinalNum(
  522. const ACardinalNum: string): Double;
  523. {
  524. function GetTotalPrice(ABillsID: Integer): Double;
  525. var
  526. stnNode: TsdIDTreeNode;
  527. begin
  528. stnNode := FBillsTree.FindNode(ABillsID);
  529. if Assigned(stnNode) then
  530. Result := stnNode.Rec.ValueByName('TotalPrice').AsFloat;
  531. end;
  532. function GetPhaseTotalPrice(ABillsID: Integer; const AType: string): Double;
  533. var
  534. Rec: TsdDataRecord;
  535. begin
  536. Rec := CurPhaseData.PhaseRecord(ABillsID);
  537. if Assigned(Rec) then
  538. Result := Rec.ValueByName(AType + 'TotalPrice').AsFloat;
  539. end;
  540. }
  541. function GetTotalPrice(ANode: TsdIDTreeNode): Double;
  542. var
  543. iChild: Integer;
  544. begin
  545. Result := 0;
  546. if not Assigned(ANode) then Exit;
  547. if ANode.HasChildren then
  548. for iChild := 0 to ANode.ChildCount - 1 do
  549. Result := Result + GetTotalPrice(ANode.ChildNodes[iChild])
  550. else
  551. Result := ANode.Rec.ValueByName('TotalPrice').AsFloat;
  552. end;
  553. function GetPhaseTotalPrice(ANode: TsdIDTreeNode; const AType: string): Double;
  554. var
  555. iChild: Integer;
  556. Rec: TsdDataRecord;
  557. begin
  558. Result := 0;
  559. if not Assigned(ANode) then Exit;
  560. if ANode.HasChildren then
  561. for iChild := 0 to ANode.ChildCount - 1 do
  562. Result := Result + GetPhaseTotalPrice(ANode.ChildNodes[iChild], AType)
  563. else
  564. begin
  565. Rec := StageData.StageRecord(ANode.ID);
  566. if Assigned(Rec) then
  567. Result := Rec.ValueByName(AType + 'TotalPrice').AsFloat;
  568. end;
  569. end;
  570. var
  571. iNodeID: Integer;
  572. begin
  573. Result := 0;
  574. iNodeID := StrToIntDef(Copy(ACardinalNum, 2, Length(ACardinalNum) - 1), -1);
  575. case ACardinalNum[1] of
  576. 'A','a': Result := GetTotalPrice(BillsMeasureTree.FindNode(iNodeID));
  577. 'B','b': Result := GetPhaseTotalPrice(BillsMeasureTree.FindNode(iNodeID), 'Deal');
  578. 'C','c': Result := GetPhaseTotalPrice(BillsMeasureTree.FindNode(iNodeID), 'Qc');
  579. 'D','d': Result := GetPhaseTotalPrice(BillsMeasureTree.FindNode(iNodeID), 'Pc');
  580. {'A','a': Result := GetTotalPrice(iNodeID);
  581. 'B','b': Result := GetPhaseTotalPrice(iNodeID, 'Deal');
  582. 'C','c': Result := GetPhaseTotalPrice(iNodeID, 'Qc');
  583. 'D','d': Result := GetPhaseTotalPrice(iNodeID, 'Pc');}
  584. end;
  585. end;
  586. function TBillsMeasureData.GetStageData: TStageData;
  587. begin
  588. Result := TProjectData(FProjectData).PhaseData.StageData;
  589. end;
  590. procedure TBillsMeasureData.ExpandNodeTo(ALevel: Integer);
  591. begin
  592. BillsMeasureTree.ExpandLevel := ALevel;
  593. end;
  594. procedure TBillsMeasureData.ExpandXmjNode;
  595. var
  596. iIndex: Integer;
  597. stnNode: TsdIDTreeNode;
  598. begin
  599. for iIndex := 0 to BillsMeasureTree.Count - 1 do
  600. begin
  601. stnNode := BillsMeasureTree.Items[iIndex];
  602. if (stnNode.ParentID <> -1) then
  603. stnNode.Parent.Expanded := stnNode.Rec.ValueByName('B_Code').AsString = '';
  604. end;
  605. end;
  606. procedure TBillsMeasureData.CalculateAll;
  607. var
  608. Cacl: TBillsCalculate;
  609. begin
  610. Cacl := TBillsCalculate.Create(Self);
  611. try
  612. Cacl.Execute;
  613. finally
  614. Cacl.Free;
  615. end;
  616. end;
  617. procedure TBillsMeasureData.UpdateRecordDeal(ABillsID: Integer; AQuantity,
  618. ATotalPrice: Double);
  619. var
  620. stnNode: TsdIDTreeNode;
  621. begin
  622. stnNode := BillsMeasureTree.FindNode(ABillsID);
  623. if not Assigned(stnNode) then Exit;
  624. with stnNode.Rec do
  625. begin
  626. if not stnNode.HasChildren then
  627. ValueByName('AddDealQuantity').AsFloat := QuantityRoundTo(
  628. ValueByName('AddDealQuantity').AsFloat + AQuantity);
  629. ValueByName('AddDealTotalPrice').AsFloat := TotalPriceRoundTo(
  630. ValueByName('AddDealTotalPrice').AsFloat + ATotalPrice);
  631. end;
  632. UpdateRecordGather(stnNode, AQuantity, ATotalPrice);
  633. UpdateRecordDeal(stnNode.ParentID, AQuantity, ATotalPrice);
  634. end;
  635. procedure TBillsMeasureData.UpdateRecordPc(ABillsID: Integer; AQuantity,
  636. ATotalPrice: Double);
  637. var
  638. stnNode: TsdIDTreeNode;
  639. begin
  640. stnNode := BillsMeasureTree.FindNode(ABillsID);
  641. if not Assigned(stnNode) then Exit;
  642. with stnNode.Rec do
  643. begin
  644. if not stnNode.HasChildren then
  645. ValueByName('AddPcQuantity').AsFloat := QuantityRoundTo(
  646. ValueByName('AddPcQuantity').AsFloat + AQuantity);
  647. ValueByName('AddPcTotalPrice').AsFloat := TotalPriceRoundTo(
  648. ValueByName('AddPcTotalPrice').AsFloat + ATotalPrice);
  649. end;
  650. UpdateRecordGather(stnNode, 0, ATotalPrice);
  651. UpdateRecordPc(stnNode.ParentID, AQuantity, ATotalPrice);
  652. end;
  653. procedure TBillsMeasureData.UpdateRecordQc(ABillsID: Integer; AQuantity,
  654. ATotalPrice: Double);
  655. var
  656. stnNode: TsdIDTreeNode;
  657. begin
  658. stnNode := BillsMeasureTree.FindNode(ABillsID);
  659. if not Assigned(stnNode) then Exit;
  660. with stnNode.Rec do
  661. begin
  662. if not stnNode.HasChildren then
  663. ValueByName('AddQcQuantity').AsFloat := QuantityRoundTo(
  664. ValueByName('AddQcQuantity').AsFloat + AQuantity);
  665. ValueByName('AddQcTotalPrice').AsFloat := TotalPriceRoundTo(
  666. ValueByName('AddQcTotalPrice').AsFloat + ATotalPrice);
  667. end;
  668. UpdateRecordGather(stnNode, AQuantity, ATotalPrice);
  669. UpdateRecordQc(stnNode.ParentID, AQuantity, ATotalPrice);
  670. end;
  671. procedure TBillsMeasureData.UpdateRecordGather(ANode: TsdIDTreeNode;
  672. AQuantity, ATotalPrice: Double);
  673. begin
  674. with ANode.Rec do
  675. begin
  676. if not ANode.HasChildren then
  677. ValueByName('AddGatherQuantity').AsFloat := QuantityRoundTo(
  678. ValueByName('AddGatherQuantity').AsFloat + AQuantity);
  679. ValueByName('AddGatherTotalPrice').AsFloat := TotalPriceRoundTo(
  680. ValueByName('AddGatherTotalPrice').AsFloat + ATotalPrice);
  681. end;
  682. CalcAddDgnPrice(ANode);
  683. CalcAddCompleteRate(ANode);
  684. end;
  685. function TBillsMeasureData.GatherRelaBGL(ANode: TsdIDTreeNode): string;
  686. var
  687. iChild: Integer;
  688. Rec: TsdDataRecord;
  689. begin
  690. Result := '';
  691. if not Assigned(ANode) then Exit;
  692. if ANode.HasChildren then
  693. begin
  694. for iChild := 0 to ANode.ChildCount - 1 do
  695. Result := MergeRelaBGL(Result, GatherRelaBGL(ANode.ChildNodes[iChild]));
  696. end
  697. else
  698. begin
  699. with TProjectData(FProjectData).PhaseData.StageData do
  700. Rec := StageRecord(ANode.ID);
  701. if Assigned(Rec) then
  702. Result := MergeRelaBGL(Rec.ValueByName('QcBGLCode').AsString, Rec.ValueByName('PcBGLCode').AsString);
  703. end;
  704. end;
  705. procedure TBillsMeasureData.sdvBillsMeasureAfterValueChanged(
  706. AValue: TsdValue);
  707. var
  708. stnNode: TsdIDTreeNode;
  709. begin
  710. if TProjectData(FProjectData).PhaseData.Active then
  711. begin
  712. if AValue.FieldName = 'Price' then
  713. StageData.ReCalculate(AValue.Owner.ValueByName('ID').AsInteger);
  714. if AValue.FieldName = 'NewPrice' then
  715. StageData.ReCalculate(AValue.Owner.ValueByName('ID').AsInteger);
  716. end;
  717. if Pos('DgnQuantity1', AValue.FieldName) > 0 then
  718. begin
  719. stnNode := BillsMeasureTree.FindNode(AValue.Owner.ValueByName('ID').AsInteger);
  720. CalcAddDgnPrice(stnNode);
  721. end;
  722. end;
  723. procedure TBillsMeasureData.ExpandCurPhase;
  724. var
  725. iIndex: Integer;
  726. stnNode: TsdIDTreeNode;
  727. StageRec: TsdDataRecord;
  728. begin
  729. for iIndex := 0 to BillsMeasureTree.Count - 1 do
  730. begin
  731. stnNode := BillsMeasureTree.Items[iIndex];
  732. StageRec := TBillsIDTreeNode(stnNode).StageRec;
  733. if (stnNode.ParentID <> -1) then
  734. if Assigned(StageRec) then
  735. stnNode.Expanded := StageRec.ValueByName('GatherTotalPrice').AsFloat <> 0
  736. else
  737. stnNode.Expanded := False;
  738. end;
  739. end;
  740. procedure TBillsMeasureData.UpdateBGLInfo(ABillsID: Integer;
  741. ARec: TsdDataRecord; const AType: string);
  742. var
  743. stnNode: TsdIDTreeNode;
  744. begin
  745. stnNode := BillsMeasureTree.FindNode(ABillsID);
  746. if not Assigned(stnNode) then Exit;
  747. stnNode.Rec.ValueByName('Add' + AType + 'BGLCode').AsString :=
  748. ARec.ValueByName('End' + AType + 'BGLCode').AsString;
  749. stnNode.Rec.ValueByName('Add' + AType + 'BGLNum').AsString :=
  750. ARec.ValueByName('End' + AType + 'BGLNum').AsString;
  751. end;
  752. function TBillsMeasureData.SelectAndUpdateBGL(ABillsID: Integer;
  753. ARec: TsdDataRecord; ANewValue: Double; const AType: string): Boolean;
  754. var
  755. AOrgBGL, ANewBGL: TBGLSelectInfo;
  756. ACurNode: TsdIDTreeNode;
  757. procedure UpdateBGL;
  758. begin
  759. ARec.ValueByName(AType + 'BGLCode').AsString := ANewBGL.MergedCode;
  760. ARec.ValueByName(AType + 'BGLNum').AsString := ANewBGL.MergedNum;
  761. TProjectData(ProjectData).BGLData.ApplyBGL(AOrgBGL, ANewBGL);
  762. end;
  763. begin
  764. Result := True;
  765. ACurNode := BillsMeasureTree.FindNode(ABillsID);
  766. AOrgBGL := TBGLSelectInfo.Create(ACurNode.Rec,
  767. ARec.ValueByName(AType + 'Quantity').AsFloat, True);
  768. AOrgBGL.MergedCode := ARec.ValueByName(AType + 'BGLCode').AsString;
  769. AOrgBGL.MergedNum := ARec.ValueByName(AType + 'BGLNum').AsString;
  770. ANewBGL := TBGLSelectInfo.Create(ACurNode.Rec, ANewValue, False);
  771. try
  772. if ANewBGL.TotalNum <> 0 then
  773. begin
  774. Result := SelectBGL(AOrgBGL, ANewBGL, ProjectData);
  775. if Result then
  776. UpdateBGL;
  777. end
  778. else
  779. UpdateBGL;
  780. StageData.UpdateBGLInfo(ARec, AType);
  781. UpdateBGLInfo(ABillsID, ARec, AType);
  782. finally
  783. AOrgBGL.Free;
  784. ANewBGL.Free;
  785. end;
  786. end;
  787. procedure TBillsMeasureData.Close;
  788. begin
  789. sdvBillsMeasure.Close;
  790. end;
  791. procedure TBillsMeasureData.CalcAddCompleteRate(ANode: TsdIDTreeNode);
  792. var
  793. fDividend, fDivisor: Double;
  794. begin
  795. with ANode.Rec do
  796. begin
  797. fDividend := ValueByName('AddGatherTotalPrice').AsFloat;
  798. fDivisor := ValueByName('TotalPrice').AsFloat + ValueByName('AddQcTotalPrice').AsFloat
  799. + ValueByName('AddPcTotalPrice').AsFloat;
  800. if fDivisor <> 0 then
  801. ValueByName('AddCompleteRate').AsFloat := AdvRoundTo(fDividend/fDivisor*100);
  802. end;
  803. end;
  804. procedure TBillsMeasureData.CalcAddDgnPrice(ANode: TsdIDTreeNode);
  805. var
  806. fDividend, fDivisor: Double;
  807. begin
  808. with ANode.Rec do
  809. begin
  810. fDividend := ValueByName('AddGatherTotalPrice').AsFloat;
  811. fDivisor := ValueByName('DealDgnQuantity1').AsFloat + ValueByName('CDgnQuantity1').AsFloat;
  812. if fDivisor <> 0 then
  813. ValueByName('AddDgnPrice').AsFloat := AdvRoundTo(fDividend/fDivisor);
  814. end;
  815. end;
  816. procedure TBillsMeasureData.SetOnRecChange(const Value: TRecChangeEvent);
  817. begin
  818. FOnRecChange := Value;
  819. end;
  820. procedure TBillsMeasureData.sdvBillsMeasureCurrentChanged(
  821. ARecord: TsdDataRecord);
  822. begin
  823. if Assigned(FOnRecChange) then
  824. FOnRecChange(ARecord);
  825. end;
  826. procedure TBillsMeasureData.ResetTreeNodeStageRec;
  827. var
  828. i: Integer;
  829. vNode: TBillsIDTreeNode;
  830. begin
  831. for i := 0 to BillsMeasureTree.Count - 1 do
  832. begin
  833. vNode := TBillsIDTreeNode(BillsMeasureTree.Items[i]);
  834. vNode.StageRec := StageData.StageRecord(vNode.ID);
  835. end;
  836. end;
  837. end.