| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286 | unit BillsCompileDm;interfaceuses  BillsDm, StandardBillsFme,  SysUtils, Classes, sdDB, BillsTree, sdIDTree, DB;type     TRefreshGridRowEvent = procedure (ARowIndex: Integer) of object;    TBillsCompileData = class(TDataModule)    sdvBillsCompile: TsdDataView;    procedure sdvBillsCompileGetText(var Text: String;      ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;      DisplayText: Boolean);    procedure sdvBillsCompileAfterValueChanged(AValue: TsdValue);    procedure sdvBillsCompileBeforeValueChange(AValue: TsdValue;      const NewValue: Variant; var Allow: Boolean);    procedure sdvBillsCompileSetText(var Text: String;      ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;      var Allow: Boolean);    procedure sdvBillsCompileAfterOpen(Sender: TObject);    procedure sdvBillsCompileAfterClose(Sender: TObject);    procedure sdvBillsCompileAfterAddRecord(ARecord: TsdDataRecord);    procedure sdvBillsCompileCurrentChanged(ARecord: TsdDataRecord);  private    FProjectData: TObject;    FBillsData: TBillsData;    FBillsCompileTree: TCompileBillsIDTree;    FOnRecChange: TRecChangeEvent;    FRefreshRow: TRefreshGridRowEvent;    function GatherChildrenOrg(ANode: TsdIDTreeNode): Double;    procedure UpdateRecordOrg(ABillsID: Integer; ATotalPrice: Double);    function FindChild(AParentNode, ANode: TsdIDTreeNode): TsdIDTreeNode;    function InsertChild(AParentNode, ANode: TsdIDTreeNode): TsdIDTreeNode;    function CompareNodeCode(ANode, ACompareNode: TsdIDTreeNode): Integer;    function GetNextSiblingID(AParent, ANode: TsdIDTreeNode): Integer;    function IsSameNode(ANode, ACompareNode: TsdIDTreeNode): Boolean;    function GetTopParentNode(ANode: TsdIDTreeNode; ALevel: Integer): TsdIDTreeNode;    procedure AddXmjBillsFromLib(AStdBillsNode: TsdIDTreeNode);    function CanAddGclBills: Boolean;    function GetGclBillsParent(AChildNode: TsdIDTreeNode): TsdIDTreeNode;    procedure AddGclBillsFromLib(AStdBillsNode: TsdIDTreeNode);    procedure DoOnAfterDeleteNode(AParent: TsdIDTreeNode);    function GatherChildren(ANode: TsdIDTreeNode; const AFieldName: string): Double;    procedure UpdateParent(ABillsID: Integer; ADifferTotalPrice: Double; const AFieldName: string);    // 经济指标[与其他节点无关]    procedure CalculateDesignPrice(ANode: TBillsIDTreeNode);    // 施工图原设计[增量]    procedure CalculateOrg(ABillsID: Integer);    // 设计错漏增减[增量]    procedure CalculateMis(ABillsID: Integer);    // 其他错漏增减[增量]    procedure CalculateOth(ABillsID: Integer);    procedure CalculateTotal(ABillsID: Integer);    procedure CalculateLeaf(ANode: TBillsIDTreeNode);    procedure GatherNode(ANode: TBillsIDTreeNode);    procedure CalculateBills(ANode: TsdIDTreeNode);    function GetActive: Boolean;    procedure SetOnRecChange(const Value: TRecChangeEvent);  public    constructor Create(AProjectData: TObject);    destructor Destroy; override;    procedure Open;    procedure Close;    procedure ReConnectTree;    procedure AddBillsFromLib(ANode: TsdIDTreeNode; ABillsType: TBillsType);    procedure AddBillsFromDealBills(ARec: TsdDataRecord);    procedure Calculate(ABillsID: Integer);    procedure CalculateAll;    function GetLeafXmjParentID(ABillsID: Integer): Integer;    procedure ExpandNodeTo(ALevel: Integer);    procedure ExpandXmjNode;    procedure ExpandPegXmjNode;    procedure ReorderChildrenCode(ANode: TsdIDTreeNode);    // 所有解锁的节点全部重新锁定    procedure ReLockBaseData;    property ProjectData: TObject read FProjectData;    property BillsData: TBillsData read FBillsData;    property BillsCompileTree: TCompileBillsIDTree read FBillsCompileTree;    property Active: Boolean read GetActive;    property OnRecChange: TRecChangeEvent read FOnRecChange write SetOnRecChange;    property RefreshRow: TRefreshGridRowEvent read FRefreshRow write FRefreshRow;  end;implementationuses  ProjectData, Math, ZhAPI, UtilMethods, ConstUnit, mDataRecord, Variants,  ConditionalDefines;{$R *.dfm}{ TBillsCompileData }constructor TBillsCompileData.Create(AProjectData: TObject);begin  inherited Create(nil);  FProjectData := AProjectData;  FBillsData := TProjectData(FProjectData).BillsData;  FBillsCompileTree := TCompileBillsIDTree.Create;  FBillsCompileTree.KeyFieldName := 'ID';  FBillsCompileTree.ParentFieldName := 'ParentID';  FBillsCompileTree.NextSiblingFieldName := 'NextSiblingID';  FBillsCompileTree.AutoCreateKeyID := True;  FBillsCompileTree.AutoExpand := True;  FBillsCompileTree.DataView := sdvBillsCompile;  FBillsCompileTree.SeedID := Max(FBillsCompileTree.SeedID, 100);  FBillsCompileTree.OnReCalcNode := Calculate;end;destructor TBillsCompileData.Destroy;begin  FBillsCompileTree.Free;  inherited;end;procedure TBillsCompileData.Open;begin  sdvBillsCompile.DataSet := TProjectData(FProjectData).BillsData.sddBills;  sdvBillsCompile.Open;  FBillsCompileTree.SeedID := Max(FBillsCompileTree.SeedID, 100);end;procedure TBillsCompileData.ReConnectTree;begin  FBillsCompileTree.DataView := nil;  FBillsCompileTree.DataView := sdvBillsCompile;end;procedure TBillsCompileData.sdvBillsCompileGetText(var Text: String;  ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;  DisplayText: Boolean);  procedure GetEditText;  var    sFormula: string;    sFormulaField: string;  begin    sFormula := '';    if ARecord.ValueByName('CalcType').AsInteger = 0 then    begin      if SameText('OrgQuantity', AColumn.FieldName) then        sFormula := ARecord.ValueByName('OrgFormula').AsString      else if SameText('MisQuantity', AColumn.FieldName) then        sFormula := ARecord.ValueByName('MisFormula').AsString      else if SameText('OthQuantity', AColumn.FieldName) then        sFormula := ARecord.ValueByName('OthFormula').AsString;    end    else if ARecord.ValueByName('CalcType').AsInteger = 1 then    begin      if SameText('OrgTotalPrice', AColumn.FieldName) then        sFormula := ARecord.ValueByName('OrgFormula').AsString      else if SameText('MisTotalPrice', AColumn.FieldName) then        sFormula := ARecord.ValueByName('MisFormula').AsString      else if SameText('OthTotalPrice', AColumn.FieldName) then        sFormula := ARecord.ValueByName('OthFormula').AsString;    end;    if sFormula <> '' then      Text := sFormula;  end;  procedure GetDisplayText;  begin    if AValue.DataType = ftFloat then    begin      if not Assigned(AValue) or (AValue.AsFloat = 0) then        Text := '';    end;  end;begin  if DisplayText then    GetDisplayText  else    GetEditText;end;procedure TBillsCompileData.ExpandNodeTo(ALevel: Integer);begin  BillsCompileTree.ExpandLevel := ALevel;end;procedure TBillsCompileData.ExpandXmjNode;var  iIndex: Integer;  stnNode: TBillsIDTreeNode;begin  for iIndex := 0 to BillsCompileTree.Count - 1 do  begin    stnNode := TBillsIDTreeNode(BillsCompileTree.Items[iIndex]);    if (stnNode.ParentID <> -1) then      stnNode.Parent.Expanded := stnNode.Rec.B_Code.AsString = '';  end;end;procedure TBillsCompileData.sdvBillsCompileAfterValueChanged(  AValue: TsdValue);  procedure ResetChildrenLockedInfo(ANode: TsdIDTreeNode; ALockedInfo: Boolean);  var    iChild: Integer;  begin    if not Assigned(ANode) then Exit;    if ANode.Rec.ValueByName('LockedLevel').AsBoolean then      ANode.Rec.ValueByName('LockedInfo').AsBoolean := ALockedInfo;    if ANode.HasChildren then      for iChild := 0 to ANode.ChildCount - 1 do        ResetChildrenLockedInfo(ANode.ChildNodes[iChild], ALockedInfo);  end;var  vNode: TBillsIDTreeNode;begin  vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(AValue.Owner.ValueByName('ID').AsInteger));  if SameText(AValue.FieldName, 'OrgQuantity') or      SameText(AValue.FieldName, 'OrgTotalPrice') then    CalculateOrg(AValue.Owner.ValueByName('ID').AsInteger)  else if SameText(AValue.FieldName, 'MisQuantity') or      SameText(AValue.FieldName, 'MisTotalPrice') then    CalculateMis(AValue.Owner.ValueByName('ID').AsInteger)  else if SameText(AValue.FieldName, 'OthQuantity') or      SameText(AValue.FieldName, 'OthTotalPrice') then    CalculateOth(AValue.Owner.ValueByName('ID').AsInteger)  else if SameText(AValue.FieldName, 'Price') then    CalculateTotal(AValue.Owner.ValueByName('ID').AsInteger)  else if SameText(AValue.FieldName, 'DgnQuantity1') then    CalculateDesignPrice(vNode);  if (AValue.FieldName = 'LockedInfo') then    ResetChildrenLockedInfo(vNode, AValue.AsBoolean);  if (AValue.FieldName = 'B_Code') then  begin    AValue.Owner.ValueByName('DgnQuantity1').Clear;    AValue.Owner.ValueByName('DgnQuantity2').Clear;    AValue.Owner.ValueByName('DgnPrice').Clear;  end;end;function TBillsCompileData.GatherChildrenOrg(ANode: TsdIDTreeNode): Double;var  iChild: Integer;begin  if ANode = nil then Exit;  if ANode.HasChildren and Assigned(ANode.FirstChild) then  begin    Result := 0;    for iChild := 0 to ANode.ChildCount - 1 do      Result := Result + GatherChildrenOrg(ANode.ChildNodes[iChild]);    Result := TotalPriceRoundTo(Result);  end  else    if Assigned(ANode.Rec) and Assigned(ANode.Rec.ValueByName('TotalPrice')) then      Result := ANode.Rec.ValueByName('TotalPrice').AsFloat    else      Result := 0;end;procedure TBillsCompileData.UpdateRecordOrg(ABillsID: Integer;  ATotalPrice: Double);var  stnNode: TsdIDTreeNode;begin  stnNode := BillsCompileTree.FindNode(ABillsID);  if not Assigned(stnNode) then Exit;  with stnNode.Rec do  begin    ValueByName('TotalPrice').AsFloat := TotalPriceRoundTo(      ValueByName('TotalPrice').AsFloat + ATotalPrice);    if ValueByName('DgnQuantity1').AsFloat <> 0 then      ValueByName('DgnPrice').AsFloat := PriceRoundTo(          ValueByName('TotalPrice').AsFloat/ValueByName('DgnQuantity1').AsFloat);  end;  UpdateRecordOrg(stnNode.ParentID, ATotalPrice);end;procedure TBillsCompileData.sdvBillsCompileBeforeValueChange(  AValue: TsdValue; const NewValue: Variant; var Allow: Boolean);    function CheckParentExist(ANode: TBillsIDTreeNode): Boolean;  var    vParent: TBillsIDTreeNode;  begin    Result := False;    vParent := TBillsIDTreeNode(ANode.Parent);    while Assigned(vParent) and not Result do    begin      if vParent.Rec.IsGatherZJJL.AsBoolean then        Result := True;      vParent := TBillsIDTreeNode(vParent.Parent);    end;  end;  procedure CancelParentCheck(ANode: TBillsIDTreeNode);  var    vParent: TBillsIDTreeNode;  begin    vParent := TBillsIDTreeNode(ANode.Parent);    while Assigned(vParent) do    begin      if vParent.Rec.IsGatherZJJL.AsBoolean then        vParent.Rec.IsGatherZJJL.AsBoolean := False;      vParent := TBillsIDTreeNode(vParent.Parent);    end;  end;  function CheckChildrenExist(ANode: TBillsIDTreeNode): Boolean;  var    iChild: Integer;    vChild: TBillsIDTreeNode;  begin    Result := False;    for iChild := 0 to ANode.ChildCount - 1 do    begin      vChild := TBillsIDTreeNode(ANode.ChildNodes[iChild]);      if vChild.Rec.IsGatherZJJL.AsBoolean or CheckChildrenExist(vChild) then      begin        Result := True;        Break;      end;    end;  end;  procedure CancelChildrenCheck(ANode: TBillsIDTreeNode);  var    iChild: Integer;    vChild: TBillsIDTreeNode;  begin    for iChild := 0 to ANode.ChildCount - 1 do    begin      vChild := TBillsIDTreeNode(ANode.ChildNodes[iChild]);      if vChild.Rec.IsGatherZJJL.AsBoolean then        vChild.Rec.IsGatherZJJL.AsBoolean := False      else        CancelChildrenCheck(vChild);    end;  end;var  vNode: TBillsIDTreeNode;begin  if SameText(AValue.FieldName, 'OrgQuantity') or      SameText(AValue.FieldName, 'MisQuantity') or      SameText(AValue.FieldName, 'OthQuantity') or      SameText(AValue.FieldName, 'OrgTotalPrice') or      SameText(AValue.FieldName, 'MisTotalPrice') or      SameText(AValue.FieldName, 'OthTotalPrice') or      SameText(AValue.FieldName, 'Price') then  begin    TBillsRecord(AValue.Owner).CacheOrgTP := AValue.Owner.ValueByName('OrgTotalPrice').AsFloat;    TBillsRecord(AValue.Owner).CacheMisTP := AValue.Owner.ValueByName('MisTotalPrice').AsFloat;    TBillsRecord(AValue.Owner).CacheOthTP := AValue.Owner.ValueByName('OthTotalPrice').AsFloat;  end  else if SameText(AValue.FieldName, 'IsGatherZJJL') then  begin    Allow := (TProjectData(FProjectData).ProjProperties.PhaseCount = 0) or TProjectData(FProjectData).CanUnlockInfo;    vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(AValue.Owner.ValueByName('ID').AsInteger));    if Allow then    begin      if CheckParentExist(vNode) then      begin        if QuestMessage('父项已勾选,继续将取消父项勾选。') then          CancelParentCheck(vNode)        else          Allow := False;      end      else if CheckChildrenExist(vNode) then      begin        if QuestMessage('子项已勾选,继续将取消子项勾选。') then          CancelChildrenCheck(vNode)        else          Allow := False;      end;    end    else      WarningMessage('开始计量后,计量汇总列不可编辑,如需修改,请先解锁。');    if not Allow and Assigned(FRefreshRow) then      RefreshRow(vNode.MajorIndex);  end;end;procedure TBillsCompileData.CalculateAll;  procedure RecursiveCalc(ANode: TsdIDTreeNode);  begin    if not Assigned(ANode) then Exit;    if ANode.HasChildren then    begin      RecursiveCalc(ANode.FirstChild);      GatherNode(TBillsIDTreeNode(ANode));    end    else      CalculateLeaf(TBillsIDTreeNode(ANode));    RecursiveCalc(ANode.NextSibling);  end;  procedure BeginCalc;  begin    sdvBillsCompile.BeforeValueChange := nil;    sdvBillsCompile.AfterValueChanged := nil;  end;  procedure EndCalc;  begin    sdvBillsCompile.BeforeValueChange := sdvBillsCompileBeforeValueChange;    sdvBillsCompile.AfterValueChanged := sdvBillsCompileAfterValueChanged;  end;begin  BeginCalc;  try    RecursiveCalc(BillsCompileTree.FirstNode);  finally    EndCalc;  end;end;procedure TBillsCompileData.AddBillsFromLib(ANode: TsdIDTreeNode;  ABillsType: TBillsType);begin  if not Assigned(ANode) then Exit;  if ABillsType = btXm then    AddXmjBillsFromLib(ANode)  else if ABillsType = btGcl then    AddGclBillsFromLib(ANode);end;procedure TBillsCompileData.AddGclBillsFromLib(  AStdBillsNode: TsdIDTreeNode);var  stnParent, stnStdNode: TsdIDTreeNode;  iLevel: Integer;begin  if not CanAddGclBills then    raise Exception.Create('当前节点下不可添加工程量清单!');  stnParent := GetGclBillsParent(BillsCompileTree.Selected);  if TBillsIDTreeNode(stnParent).HasLedger or     (not stnParent.HasChildren and TBillsIDTreeNode(stnParent).HasMeasure) then    raise Exception.Create('当前节点不可添加工程量清单!');  stnStdNode := GetTopParentNode(AStdBillsNode, AStdBillsNode.Level);  for iLevel := 1 to AStdBillsNode.Level + 1 do  begin    if stnStdNode.Rec.ValueByName('B_Code').AsString <> '' then      if FindChild(stnParent, stnStdNode) <> nil then        stnParent := FindChild(stnParent, stnStdNode)      else        stnParent := InsertChild(stnParent, stnStdNode);    stnStdNode := GetTopParentNode(AStdBillsNode, AStdBillsNode.Level - iLevel);  end;end;procedure TBillsCompileData.AddXmjBillsFromLib(  AStdBillsNode: TsdIDTreeNode);var  stnStdNode, stnCurNode: TsdIDTreeNode;  iLevel: Integer;begin  stnStdNode := GetTopParentNode(AStdBillsNode, AStdBillsNode.Level);  stnCurNode := nil;  for iLevel := 1 to AStdBillsNode.Level + 1 do  begin    if FindChild(stnCurNode, stnStdNode) <> nil then      stnCurNode := FindChild(stnCurNode, stnStdNode)    else if Assigned(stnCurNode) then    begin      if TBillsIDTreeNode(stnCurNode).HasLedger or          (not stnCurNode.HasChildren and TBillsIDTreeNode(stnCurNode).HasMeasure) then        raise Exception.Create('不可添加该项目节数据!')      else        stnCurNode := InsertChild(stnCurNode, stnStdNode);    end    else      Break;    stnStdNode := GetTopParentNode(AStdBillsNode, AStdBillsNode.Level - iLevel);  end;end;function TBillsCompileData.CanAddGclBills: Boolean;  function CheckChildrenHasXmj(ANode: TsdIDTreeNode): Boolean;  var    stnCurNode: TsdIDTreeNode;  begin    Result := False;    if not ANode.HasChildren then Exit;    stnCurNode := ANode.FirstChild;    while not Result and Assigned(stnCurNode) do    begin      Result := Result or (stnCurNode.Rec.ValueByName('Code').AsString <> '');      if stnCurNode.HasChildren then        Result := Result or CheckChildrenHasXmj(stnCurNode);      stnCurNode := stnCurNode.NextSibling;    end;  end;  function CheckParentIsXmj(ANode: TsdIDTreeNode): Boolean;  begin    Result := False;    if not Assigned(ANode) then Exit;    Result := ANode.Rec.ValueByName('Code').AsString <> '';    if not Result then      Result := Result or CheckParentIsXmj(ANode.Parent);  end;begin  Result := False;  if not Assigned(BillsCompileTree.Selected) then Exit;  Result := CheckParentIsXmj(BillsCompileTree.Selected)    and not CheckChildrenHasXmj(BillsCompileTree.Selected);end;function TBillsCompileData.CompareNodeCode(ANode,  ACompareNode: TsdIDTreeNode): Integer;begin  if ANode.Rec.ValueByName('Code').AsString <> '' then    Result := CompareCode(ANode.Rec.ValueByName('Code').AsString,      ACompareNode.Rec.ValueByName('Code').AsString)  else if ANode.Rec.ValueByName('B_Code').AsString <> '' then    Result := CompareCode(ANode.Rec.ValueByName('B_Code').AsString,      ACompareNode.Rec.ValueByName('B_Code').AsString);end;function TBillsCompileData.GetGclBillsParent(  AChildNode: TsdIDTreeNode): TsdIDTreeNode;begin  if AChildNode.Rec.ValueByName('B_Code').AsString <> '' then    Result := GetGclBillsParent(AChildNode.Parent)  else    Result := AChildNode;end;function TBillsCompileData.GetNextSiblingID(AParent,  ANode: TsdIDTreeNode): Integer;var  stnCurNode: TsdIDTreeNode;begin  Result := -1;  if Assigned(AParent) then    stnCurNode := AParent.FirstChild  else    stnCurNode := BillsCompileTree.FirstNode;  if not Assigned(stnCurNode) then Exit;  while Assigned(stnCurNode) do  begin    if CompareNodeCode(stnCurNode, ANode) >= 0 then    begin      Result := stnCurNode.ID;      Exit;    end;    stnCurNode := stnCurNode.NextSibling;  end;end;function TBillsCompileData.GetTopParentNode(ANode: TsdIDTreeNode;  ALevel: Integer): TsdIDTreeNode;begin  Result := ANode;  while Assigned(Result.Parent) and (Result.Level + ALevel > ANode.Level) do    Result := Result.Parent;end;function TBillsCompileData.IsSameNode(ANode,  ACompareNode: TsdIDTreeNode): Boolean;begin  if ANode.Rec.ValueByName('StaticID').AsInteger > 0 then    Result := (ANode.Rec.ValueByName('StaticID').AsInteger = ACompareNode.Rec.ValueByName('ID').AsInteger)  else    Result := (ANode.Rec.ValueByName('Code').AsString = ACompareNode.Rec.ValueByName('Code').AsString)          and (ANode.Rec.ValueByName('B_Code').AsString = ACompareNode.Rec.ValueByName('B_Code').AsString)          and (ANode.Rec.ValueByName('Name').AsString = ACompareNode.Rec.ValueByName('Name').AsString);end;function TBillsCompileData.FindChild(AParentNode,  ANode: TsdIDTreeNode): TsdIDTreeNode;  function FindSibling(AFirstNode, ANode: TsdIDTreeNode): TsdIDTreeNode;  var    stnCurNode: TsdIDTreeNode;  begin    Result := nil;    stnCurNode := AFirstNode;    while Assigned(stnCurNode) and not Assigned(Result) do    begin      if IsSameNode(ANode, stnCurNode) then        Result := stnCurNode;      stnCurNode := stnCurNode.NextSibling;    end;  end;begin  if not Assigned(AParentNode) then    Result := FindSibling(BillsCompileTree.FirstNode, ANode)  else    Result := FindSibling(AParentNode.FirstChild, ANode);end;function TBillsCompileData.InsertChild(AParentNode,  ANode: TsdIDTreeNode): TsdIDTreeNode;var  iID, iNextSiblingID: Integer;begin  iNextSiblingID := GetNextSiblingID(AParentNode, ANode);  iID := ANode.Rec.ValueByName('StaticID').AsInteger;  if Assigned(AParentNode) then    Result := BillsCompileTree.AddNode(AParentNode.ID, iNextSiblingID, iID)  else    Result := BillsCompileTree.AddNode(-1, iNextSiblingID, iID);  Result.Rec.ValueByName('Code').AsString := ANode.Rec.ValueByName('Code').AsString;  Result.Rec.ValueByName('B_Code').AsString := ANode.Rec.ValueByName('B_Code').AsString;  Result.Rec.ValueByName('Name').AsString := ANode.Rec.ValueByName('Name').AsString;  Result.Rec.ValueByName('Units').AsString := ANode.Rec.ValueByName('Unit').AsString;end;procedure TBillsCompileData.sdvBillsCompileSetText(var Text: String;  ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;  var Allow: Boolean);  procedure SetTextErrorHint(const AHint: string);  begin    ErrorMessage(AHint);    Allow := False;  end;  procedure SetQuantity(const AFieldName: string);  var    sPre: string;  begin    sPre := StringReplace(AFieldName, 'Quantity', '', [rfIgnoreCase, rfReplaceAll]);    if CheckStringNull(Text) or CheckNumeric(Text) then    begin      ARecord.ValueByName(sPre + 'Formula').AsString := '';      Text := FloatToStr(QuantityRoundTo(StrToFloatDef(Text, 0)));    end    else    begin      ARecord.ValueByName(sPre + 'Formula').AsString := Text;      Text := FloatToStr(QuantityRoundTo(EvaluateExprs(Text)));    end;    ARecord.ValueByName('CalcType').AsInteger := 0;  end;  procedure SetTotalPrice(const AFieldName: string);  var    sPre: string;  begin    sPre := StringReplace(AFieldName, 'TotalPrice', '', [rfIgnoreCase, rfReplaceAll]);    if CheckStringNull(Text) or CheckNumeric(Text) then    begin      ARecord.ValueByName(sPre + 'Formula').AsString := '';      Text := FloatToStr(TotalPriceRoundTo(StrToFloatDef(Text, 0)));    end    else    begin      ARecord.ValueByName(sPre + 'Formula').AsString := Text;      Text := FloatToStr(TotalPriceRoundTo(EvaluateExprs(Text)));    end;    ARecord.ValueByName('CalcType').AsInteger := 1;  end;  procedure SetDgnQuantity;  begin    Text := FloatToStr(QuantityRoundTo(StrToFloatDef(Text, 0)));  end;  procedure SetPrice;  begin    Text := FloatToStr(PriceRoundTo(StrToFloatDef(Text, 0)));    ARecord.ValueByName('CalcType').AsInteger := 0;  end;  procedure DoCurChanged(ANode: TBillsIDTreeNode);  begin    if SameText(AColumn.FieldName, 'OrgQuantity') or        SameText(AColumn.FieldName, 'MisQuantity') or        SameText(AColumn.FieldName, 'OthQuantity')then      SetQuantity(AColumn.FieldName)    else if SameText(AColumn.FieldName, 'OrgTotalPrice') or        SameText(AColumn.FieldName, 'MisTotalPrice') or        SameText(AColumn.FieldName, 'OthTotalPrice') then      SetTotalPrice(AColumn.FieldName)    else if Pos('DgnQuantity', AColumn.FieldName) = 1 then      SetDgnQuantity    else if SameText(AColumn.FieldName, 'Price') then      SetPrice    else if SameText(AColumn.FieldName, 'Code') then      BillsCompileTree.RecodeChildrenCode(ANode, AValue.AsString, Text)    else if SameText(AColumn.FieldName, 'B_Code') then      BillsCompileTree.RecodeChildrenB_Code(ANode, AValue.AsString, Text);  end;  procedure CheckLockedData;  begin    if SameText(AColumn.FieldName, 'Code') or       SameText(AColumn.FieldName, 'B_Code') or       SameText(AColumn.FieldName, 'Name') or       SameText(AColumn.FieldName, 'Units') or       SameText(AColumn.FieldName, 'Price') or       SameText(AColumn.FieldName, 'OrgQuantity') or       SameText(AColumn.FieldName, 'OrgTotalPrice') or       SameText(AColumn.FieldName, 'MisQuantity') or       SameText(AColumn.FieldName, 'MisTotalPrice') or       SameText(AColumn.FieldName, 'OthQuantity') or       SameText(AColumn.FieldName, 'OthTotalPrice') or       SameText(AColumn.FieldName, 'DrawingCode')then       if ARecord.ValueByName('LockedInfo').AsBoolean then         SetTextErrorHint('清单信息已被锁定,不允许修改编号、名称、单位、清单单价、0号台账数量与金额、图号!');  end;  procedure CheckNodeWritable(ANode: TBillsIDTreeNode);  var    iCreatePhase: Integer;  begin    if not Allow then Exit;    iCreatePhase := ANode.Rec.ValueByName('CreatePhaseID').AsInteger;    if ANode.ID = iPriceMarginID then      SetTextErrorHint(sBills_PMHint);    if ANode.HasChildren then    begin      if Text = '' then        Exit      else if ((Pos('Quantity', AColumn.FieldName) > 0) and (Pos('Dgn', AColumn.FieldName) <=0)) or          (Pos('TotalPrice', AColumn.FieldName) > 0) then        SetTextErrorHint('该清单有子计算项,不能直接修改!')      else if (Pos('Price', AColumn.FieldName) > 0) then        SetTextErrorHint('仅最底层清单可输入单价!');      if not Allow then Exit;    end    else    begin      if SameText('OrgTotalPrice', AColumn.FieldName) or          SameText('MisTotalPrice', AColumn.FieldName) or          SameText('OthTotalPrice', AColumn.FieldName) then      begin        if not ANode.TotalPriceEnable then          SetTextErrorHint('该清单不可直接输入金额,如需直接输入金额,请先清空所有数量、单价!');      end;      if not Allow then Exit;      if SameText('Price', AColumn.FieldName) or          SameText('OrgQuantity', AColumn.FieldName) or          SameText('MisQuantity', AColumn.FieldName) or          SameText('OthQuantity', AColumn.FieldName) then      begin        if not ANode.CountPriceEnable then          SetTextErrorHint('该清单不可输入数量单价,如需使用数量×单价计算,请先清空所有直接输入的金额!');      end;      if not Allow then Exit;    end;    // 清单编号和项目节编号不可同时存在    if SameText(AValue.FieldName, 'Code') then    begin      if AValue.Owner.ValueByName('B_Code').AsString <> '' then        SetTextErrorHint('已存在清单编号,不可输入项目节编号!');    end    else if SameText(AValue.FieldName, 'B_Code') then    begin      if AValue.Owner.ValueByName('Code').AsString <> '' then        SetTextErrorHint('已存在项目节编号,不可输入清单编号!');    end    //    else if SameText(AValue.FieldName, 'Price') then    begin      if AValue.Owner.ValueByName('AddGatherTotalPrice').AsFloat <> 0 then        SetTextErrorHint('该清单已经开始计量,不可修改单价!');    end    // 变更清单不可修改0号台账数据    else if SameText(AValue.FieldName, 'OrgQuantity') or        SameText(AValue.FieldName, 'OrgTotalPrice') or        SameText(AValue.FieldName, 'MisQuantity') or        SameText(AValue.FieldName, 'MisTotalPrice') or        SameText(AValue.FieldName, 'OthQuantity') or        SameText(AValue.FieldName, 'OthTotalPrice') then    begin      if AValue.Owner.ValueByName('IsMeasureAdd').AsBoolean then        SetTextErrorHint('变更清单不可填写0号台账数量与金额');    end;    if not Allow then Exit;    if SameText('Code', AColumn.FieldName) or       SameText('B_Code', AColumn.FieldName) or       SameText('Name', AColumn.FieldName) or       SameText('Units', AColumn.FieldName) or       SameText('Price', AColumn.FieldName) then      if TBillsIDTreeNode(ANode).HasMeasure then        SetTextErrorHint('该清单已经计量,不可修改清单编号');  end;  function CheckValidData: Boolean;  begin    Result := (AValue.AsString <> Text);    if SameText(AColumn.FieldName, 'OrgQuantity') or       SameText(AColumn.FieldName, 'OrgTotalPrice') or       SameText(AColumn.FieldName, 'MisQuantity') or       SameText(AColumn.FieldName, 'MisTotalPrice') or       SameText(AColumn.FieldName, 'OthQuantity') or       SameText(AColumn.FieldName, 'OthTotalPrice') or       SameText(AColumn.FieldName, 'Price') then    begin      if (AValue.AsFloat = 0) and (Text = '') then        Result := False;    end;  end;var  vNode: TBillsIDTreeNode;begin  if not Assigned(AValue) then Exit;  // 修改后数据与原数据相同则不提交  if not CheckValidData then    Allow := False;  if not Allow then Exit;  vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ARecord.ValueByName('ID').AsInteger));  CheckLockedData;  if not Allow then Exit;  CheckNodeWritable(vNode);  if not Allow then Exit;  Text := Trim(Text);  if Pos('=', Text) = 1 then    Text := Copy(Text, 2, Length(Text) - 1);  DoCurChanged(vNode);end;function TBillsCompileData.GetActive: Boolean;begin  Result := sdvBillsCompile.Active;end;function TBillsCompileData.GetLeafXmjParentID(ABillsID: Integer): Integer;var  stnNode: TsdIDTreeNode;begin  stnNode := BillsCompileTree.FindNode(ABillsID);  Result := GetGclBillsParent(stnNode).ID;end;procedure TBillsCompileData.sdvBillsCompileAfterOpen(Sender: TObject);begin  BillsCompileTree.Active := True;end;procedure TBillsCompileData.sdvBillsCompileAfterClose(Sender: TObject);begin  BillsCompileTree.Active := False;end;procedure TBillsCompileData.ReorderChildrenCode(ANode: TsdIDTreeNode);var  iChild: Integer;  sParentCode: string;  stnChild: TsdIDTreeNode;begin  if not Assigned(ANode) then Exit;  sParentCode := ANode.Rec.ValueByName('Code').AsString;  for iChild := 0 to ANode.ChildCount - 1 do  begin    stnChild := ANode.ChildNodes[iChild];    if stnChild.Rec.ValueByName('Code').AsString <> '' then      stnChild.Rec.ValueByName('Code').AsString := sParentCode + '-' + IntToStr(iChild + 1);    ReorderChildrenCode(stnChild);  end;end;procedure TBillsCompileData.sdvBillsCompileAfterAddRecord(  ARecord: TsdDataRecord);begin  // 解锁前,新增清单为变更清单,解锁后,新增清单为0号台账清单  if TProjectData(FProjectData).ProjProperties.PhaseCount > 0 then    ARecord.ValueByName('IsMeasureAdd').AsBoolean := not TProjectData(FProjectData).CanUnlockInfo;end;procedure TBillsCompileData.DoOnAfterDeleteNode(AParent: TsdIDTreeNode);begin  if Assigned(AParent) and (AParent.ID > 0) then    Calculate(AParent.ID);end;procedure TBillsCompileData.Close;begin  sdvBillsCompile.Close;end;procedure TBillsCompileData.SetOnRecChange(const Value: TRecChangeEvent);begin  FOnRecChange := Value;end;procedure TBillsCompileData.sdvBillsCompileCurrentChanged(  ARecord: TsdDataRecord);begin  if Assigned(FOnRecChange) then    FOnRecChange(ARecord);end;procedure TBillsCompileData.ReLockBaseData;  procedure LockNodeBaseData(ANode: TsdIDTreeNode);  begin    if not Assigned(ANode) then Exit;    if ANode.Rec.ValueByName('LockedLevel').AsBoolean then      if not ANode.Rec.ValueByName('LockedInfo').AsBoolean then        ANode.Rec.ValueByName('LockedInfo').AsBoolean := True;    LockNodeBaseData(ANode.FirstChild);    LockNodeBaseData(ANode.NextSibling);  end;begin  sdvBillsCompile.AfterValueChanged := nil;  try    LockNodeBaseData(FBillsCompileTree.FirstNode);  finally    sdvBillsCompile.AfterValueChanged := sdvBillsCompileAfterValueChanged;  end;end;procedure TBillsCompileData.AddBillsFromDealBills(ARec: TsdDataRecord);var  stnParent, stnNode: TsdIDTreeNode;begin  if not CanAddGclBills then    raise Exception.Create('当前节点下不可添加工程量清单!');  stnParent := GetGclBillsParent(BillsCompileTree.Selected);  if TBillsIDTreeNode(stnParent).HasLedger or     (not stnParent.HasChildren and TBillsIDTreeNode(stnParent).HasMeasure) then    raise Exception.Create('当前节点不可添加工程量清单!');  stnNode := BillsCompileTree.Add(stnParent.ID, -1);  stnNode.Rec.ValueByName('B_Code').AsString := ARec.ValueByName('B_Code').AsString;  stnNode.Rec.ValueByName('Name').AsString := ARec.ValueByName('Name').AsString;  stnNode.Rec.ValueByName('Units').AsString := ARec.ValueByName('Units').AsString;  stnNode.Rec.ValueByName('Price').AsString := ARec.ValueByName('Price').AsString;end;procedure TBillsCompileData.CalculateMis(ABillsID: Integer);var  vNode: TBillsIDTreeNode;  iChild: Integer;begin  vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));  if not Assigned(vNode) then Exit;  if vNode.HasChildren then  begin    for iChild := 0 to vNode.ChildCount - 1 do      CalculateMis(vNode.ChildNodes[iChild].ID);  end  else  begin    with vNode.Rec do    begin      // 数量单价模式则计算金额      if CalcType.AsInteger = 0 then        MisTotalPrice.AsFloat := TotalPriceRoundTo(MisQuantity.AsFloat * Price.AsFloat);      SetFloatValue(Quantity, QuantityRoundTo(          OrgQuantity.AsFloat + MisQuantity.AsFloat + OthQuantity.AsFloat));       // 金额与修改前不一样,则向父项增量      if MisTotalPrice.AsFloat <> CacheMisTP then      begin        UpdateParent(vNode.ParentID, MisTotalPrice.AsFloat - CacheMisTP, 'MisTotalPrice');        TotalPrice.AsFloat := TotalPriceRoundTo(            OrgTotalPrice.AsFloat + MisTotalPrice.AsFloat + OthTotalPrice.AsFloat);        CacheMisTP := MisTotalPrice.AsFloat;      end;    end;  end;  CalculateDesignPrice(vNode);end;procedure TBillsCompileData.CalculateOrg(ABillsID: Integer);var  vNode: TBillsIDTreeNode;  iChild: Integer;  fValue: Double;begin  vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));  if not Assigned(vNode) then Exit;  if vNode.HasChildren then  begin    for iChild := 0 to vNode.ChildCount - 1 do      CalculateOrg(vNode.ChildNodes[iChild].ID);  end  else  begin    with vNode.Rec do    begin      // 数量单价模式则计算金额      if CalcType.AsInteger = 0 then        OrgTotalPrice.AsFloat := TotalPriceRoundTo(OrgQuantity.AsFloat * Price.AsFloat);      SetFloatValue(Quantity, QuantityRoundTo(          OrgQuantity.AsFloat + MisQuantity.AsFloat + OthQuantity.AsFloat));      // 金额与修改前不一样,则向父项增量      if CacheOrgTP <> OrgTotalPrice.AsFloat then      begin        UpdateParent(vNode.ParentID, OrgTotalPrice.AsFloat - CacheOrgTP, 'OrgTotalPrice');        TotalPrice.AsFloat := TotalPriceRoundTo(            OrgTotalPrice.AsFloat + MisTotalPrice.AsFloat + OthTotalPrice.AsFloat);        CacheOrgTP := OrgTotalPrice.AsFloat;      end;    end;  end;  CalculateDesignPrice(vNode);end;procedure TBillsCompileData.CalculateOth(ABillsID: Integer);var  vNode: TBillsIDTreeNode;  iChild: Integer;begin  vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));  if not Assigned(vNode) then Exit;  if vNode.HasChildren then  begin    for iChild := 0 to vNode.ChildCount - 1 do      CalculateOth(vNode.ChildNodes[iChild].ID);  end  else  begin    with vNode.Rec do    begin      // 数量单价模式则计算金额      if CalcType.AsInteger = 0 then        OthTotalPrice.AsFloat := TotalPriceRoundTo(OthQuantity.AsFloat * Price.AsFloat);      SetFloatValue(Quantity, QuantityRoundTo(          OrgQuantity.AsFloat + MisQuantity.AsFloat + OthQuantity.AsFloat));      // 金额与修改前不一样,则向父项增量      if OthTotalPrice.AsFloat <> CacheOthTP then      begin        UpdateParent(vNode.ParentID, OthTotalPrice.AsFloat - CacheOthTP, 'OthTotalPrice');        TotalPrice.AsFloat := TotalPriceRoundTo(            OrgTotalPrice.AsFloat + MisTotalPrice.AsFloat+ OthTotalPrice.AsFloat);        CacheOthTP := OthTotalPrice.AsFloat;      end;    end;  end;  CalculateDesignPrice(vNode);end;function TBillsCompileData.GatherChildren(ANode: TsdIDTreeNode;  const AFieldName: string): Double;var  iChild: Integer;begin  Result := 0;  if not Assigned(ANode) then Exit;  if ANode.HasChildren and Assigned(ANode.FirstChild) then  begin    Result := 0;    for iChild := 0 to ANode.ChildCount - 1 do      Result := Result + ANode.Rec.ValueByName(AFieldName).AsFloat;    Result := TotalPriceRoundTo(Result);  end  else    if Assigned(ANode.Rec) and Assigned(ANode.Rec.ValueByName(AFieldName)) then      Result := ANode.Rec.ValueByName(AFieldName).AsFloat;end;procedure TBillsCompileData.UpdateParent(ABillsID: Integer;  ADifferTotalPrice: Double; const AFieldName: string);var  vNode: TBillsIDTreeNode;begin  vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));  if not Assigned(vNode) then Exit;  with vNode.Rec do  begin    ValueByName(AFieldName).AsFloat := TotalPriceRoundTo(        ValueByName(AFieldName).AsFloat + ADifferTotalPrice);    TotalPrice.AsFloat := TotalPriceRoundTo(TotalPrice.AsFloat + ADifferTotalPrice);  end;  CalculateDesignPrice(vNode);  UpdateParent(vNode.ParentID, ADifferTotalPrice, AFieldName);end;procedure TBillsCompileData.CalculateTotal(ABillsID: Integer);begin  CalculateOrg(ABillsID);  CalculateMis(ABillsID);  CalculateOth(ABillsID);end;procedure TBillsCompileData.CalculateBills(ANode: TsdIDTreeNode);var  iChild: Integer;begin  if not Assigned(ANode) then Exit;  if ANode.HasChildren then  begin    for iChild := 0 to ANode.ChildCount - 1 do      CalculateBills(ANode.ChildNodes[iChild]);    GatherNode(TBillsIDTreeNode(ANode));  end  else    CalculateLeaf(TBillsIDTreeNode(ANode));end;procedure TBillsCompileData.CalculateLeaf(ANode: TBillsIDTreeNode);begin  if not Assigned(ANode) or ANode.HasChildren then Exit;  with ANode.Rec do  begin    // 分项    if CalcType.AsFloat = 0 then    begin      OrgTotalPrice.AsFloat := TotalPriceRoundTo(Price.AsFloat * OrgQuantity.AsFloat);      MisTotalPrice.AsFloat := TotalPriceRoundTo(Price.AsFloat * MisQuantity.AsFloat);      OthTotalPrice.AsFloat := TotalPriceRoundTo(Price.AsFloat * OthQuantity.AsFloat);    end;    // 汇总    Quantity.AsFloat := QuantityRoundTo(        OrgQuantity.AsFloat + MisQuantity.AsFloat + OthQuantity.AsFloat);    TotalPrice.AsFloat := TotalPriceRoundTo(        OrgTotalPrice.AsFloat + MisTotalPrice.AsFloat + OthTotalPrice.AsFloat);  end;  CalculateDesignPrice(ANode);end;procedure TBillsCompileData.GatherNode(ANode: TBillsIDTreeNode);var  iChild: Integer;  fOrg, fMis, fOth: Double;  vChild: TBillsIDTreeNode;begin  fOrg := 0;  fMis := 0;  fOth := 0;  for iChild := 0 to ANode.ChildCount - 1 do  begin    vChild := TBillsIDTreeNode(ANode.ChildNodes[iChild]);    fOrg := fOrg + vChild.Rec.OrgTotalPrice.AsFloat;    fMis := fMis + vChild.Rec.MisTotalPrice.AsFloat;    fOth := fOth + vChild.Rec.OthTotalPrice.AsFloat;  end;  ANode.Rec.OrgTotalPrice.AsFloat := TotalPriceRoundTo(fOrg);  ANode.Rec.MisTotalPrice.AsFloat := TotalPriceRoundTo(fMis);  ANode.Rec.OthTotalPrice.AsFloat := TotalPriceRoundTo(fOth);  ANode.Rec.TotalPrice.AsFloat := TotalPriceRoundTo(fOrg + fMis + fOth);  CalculateDesignPrice(ANode);end;procedure TBillsCompileData.Calculate(ABillsID: Integer);  procedure UpdateParent(ANode: TBillsIDTreeNode; ADifferOrg, ADifferMis, ADifferOth: Double);  begin    if not Assigned(ANode) then Exit;    with ANode.Rec do    begin      OrgTotalPrice.AsFloat := TotalPriceRoundTo(OrgTotalPrice.AsFloat + ADifferOrg);      MisTotalPrice.AsFloat := TotalPriceRoundTo(MisTotalPrice.AsFloat + ADifferMis);      OthTotalPrice.AsFloat := TotalPriceRoundTo(OthTotalPrice.AsFloat + ADifferOth);      TotalPrice.AsFloat := TotalPriceRoundTo(          TotalPrice.AsFloat + ADifferOrg + ADifferMis + ADifferOth);      if DgnQuantity1.AsFloat <> 0 then        DgnPrice.AsFloat := PriceRoundTo(TotalPrice.AsFloat/DgnQuantity1.AsFloat);    end;    UpdateParent(TBillsIDTreeNode(ANode.Parent), ADifferOrg, ADifferMis, ADifferOth);  end;var  vNode: TBillsIDTreeNode;  iChild: Integer;  fOrg, fMis, fOth: Double;begin  vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));  if not Assigned(vNode) then Exit;  fOrg := vNode.Rec.OrgTotalPrice.AsFloat;  fMis := vNode.Rec.MisTotalPrice.AsFloat;  fOth := vNode.Rec.OthTotalPrice.AsFloat;  CalculateBills(vNode);  fOrg := vNode.Rec.OrgTotalPrice.AsFloat - fOrg;  fMis := vNode.Rec.MisTotalPrice.AsFloat - fMis;  fOth := vNode.Rec.OthTotalPrice.AsFloat - fOth;  UpdateParent(TBillsIDTreeNode(vNode.Parent), fOrg, fMis, fOth);end;procedure TBillsCompileData.CalculateDesignPrice(ANode: TBillsIDTreeNode);begin  if QuantityRoundTo(ANode.Rec.DgnQuantity1.AsFloat) <> 0 then    ANode.Rec.DgnPrice.AsFloat := PriceRoundTo(        ANode.Rec.TotalPrice.AsFloat/ANode.Rec.DgnQuantity1.AsFloat)  else    ANode.Rec.DgnPrice.Clear;end;procedure TBillsCompileData.ExpandPegXmjNode;  function HasPegChild(ANode: TBillsIDTreeNode): Boolean;  var    NextNode: TBillsIDTreeNode;  begin    Result := False;    NextNode := TBillsIDTreeNode(ANode.NextNode);    while ((NextNode.MajorIndex - ANode.MajorIndex) <= ANode.PosterityCount) do    begin      if CheckPeg(NextNode.Rec.Name.AsString) then      begin        Result := True;        Break;      end;      NextNode := TBillsIDTreeNode(NextNode.NextNode);    end;  end;  function HasGclChild(ANode: TBillsIDTreeNode): Boolean;  var    vChild: TBillsIDTreeNode;  begin    Result := True;    vChild := TBillsIDTreeNode(ANode.FirstChild);    while Assigned(vChild) and not Result do    begin      if vChild.Rec.B_Code.AsString <> '' then        Result := False;      vChild := TBillsIDTreeNode(vChild.NextSibling);    end;  end;var  iIndex: Integer;  vNode: TBillsIDTreeNode;begin  for iIndex := 0 to BillsCompileTree.Count - 1 do  begin    vNode := TBillsIDTreeNode(BillsCompileTree.Items[iIndex]);    if vNode.HasChildren then      vNode.Expanded := HasPegChild(vNode) or not HasGclChild(vNode);  end;end;end.
 |