BillsMeasureDm.pas 32 KB

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