unit BillsTree; interface uses sdIDTree, sdDB, mDataRecord; type TBillsIDTreeNode = class(TsdIDTreeNode) private FStageRec: TStageRecord; FDealQuantity: Double; FDealTotalPrice: Double; FQcQuantity: Double; FQcTotalPrice: Double; FPcQuantity: Double; FPcTotalPrice: Double; FGatherTotalPrice: Double; FGatherQuantity: Double; function HasCountPrice: Boolean; function HasTotalPrice: Boolean; function GetRec: TBillsRecord; function GetChapterParentID: Integer; function GetChapterParent: TBillsIDTreeNode; public function CanUpLevel: Boolean; override; function CanDownLevel: Boolean; override; function CanUpMove: Boolean; override; function CanDownMove: Boolean; override; function UpLevel: Boolean; override; function DownLevel: Boolean; override; function HasMeasure: Boolean; function HasLedger: Boolean; function CountPriceEnable: Boolean; function TotalPriceEnable: Boolean; property Rec: TBillsRecord read GetRec; property ChapterParent: TBillsIDTreeNode read GetChapterParent; property ChapterParentID: Integer read GetChapterParentID; property DealQuantity: Double read FDealQuantity write FDealQuantity; property DealTotalPrice: Double read FDealTotalPrice write FDealTotalPrice; property QcQuantity: Double read FQcQuantity write FQcQuantity; property QcTotalPrice: Double read FQcTotalPrice write FQcTotalPrice; property PcQuantity: Double read FPcQuantity write FPcQuantity; property PcTotalPrice: Double read FPcTotalPrice write FPcTotalPrice; property GatherQuantity: Double read FGatherQuantity write FGatherQuantity; property GatherTotalPrice: Double read FGatherTotalPrice write FGatherTotalPrice; // Cache Data property StageRec: TStageRecord read FStageRec write FStageRec; end; TReCalculateNode = procedure(AID: Integer) of object; TBillsIDTree = class(TsdIDTree) protected function CreateItem: TsdIDTreeNode; override; public function CanDelete(ANode: TsdIDTreeNode): Boolean; override; function DeleteNode(ANode: TsdIDTreeNode): Boolean; override; function Add(AParentID, ANextSiblingID: TsdTreeNodeID): TsdIDTreeNode; override; procedure RecodeChildrenCode(ANode: TBillsIDTreeNode; AOrgCode, ANewCode: string); procedure RecodeChildrenB_Code(ANode: TBillsIDTreeNode; AOrgCode, ANewCode: string); procedure DoOnReCalcNode(AID: Integer); overload; virtual; abstract; procedure DoOnReCalcNode(ANode: TsdIDTreeNode); overload; virtual; abstract; end; TCompileBillsIDTree = class(TBillsIDTree) private FOnReCalcNode: TReCalculateNode; public procedure DoOnReCalcNode(AID: Integer); overload; override; procedure DoOnReCalcNode(ANode: TsdIDTreeNode); overload; override; property OnReCalcNode: TReCalculateNode read FOnReCalcNode write FOnReCalcNode; end; TMeasureBillsIDTreeNode = class(TBillsIDTreeNode) private FStageRec: TStageRecord; public // Cache Data property StageRec: TStageRecord read FStageRec write FStageRec; end; TMeasureBillsIDTree = class(TBillsIDTree) private FCompileTree: TCompileBillsIDTree; protected function CreateItem: TsdIDTreeNode; override; public procedure DoOnReCalcNode(AID: Integer); overload; override; procedure DoOnReCalcNode(ANode: TsdIDTreeNode); overload; override; property CompileTree: TCompileBillsIDTree read FCompileTree write FCompileTree; end; TEstimateIDTreeNode = class(TsdIDTreeNode) public function CanExpand: Boolean; override; end; TEstimateIDTree = class(TsdIDTree) public function CreateItem: TsdIDTreeNode; override; end; implementation uses SysUtils; { TBillsIDTree } function TBillsIDTree.Add(AParentID, ANextSiblingID: TsdTreeNodeID): TsdIDTreeNode; begin // 不允许插入首层节点 if (Selected <> nil) and (Selected.Level = 0) then Result := inherited Add(Selected.ID, -1) else Result := inherited Add(AParentID, ANextSiblingID); end; function TBillsIDTree.CanDelete(ANode: TsdIDTreeNode): Boolean; begin Result := Inherited CanDelete(ANode) and (ANode.ID >= 100) and (not ANode.Rec.ValueByName('LockedLevel').AsBoolean) and (ANode.Rec.ValueByName('AddDealQuantity').AsFloat = 0) and (ANode.Rec.ValueByName('AddDealTotalPrice').AsFloat = 0) and (ANode.Rec.ValueByName('AddQcQuantity').AsFloat = 0) and (ANode.Rec.ValueByName('AddQcTotalPrice').AsFloat = 0) and (ANode.Rec.ValueByName('AddPcQuantity').AsFloat = 0) and (ANode.Rec.ValueByName('AddPcTotalPrice').AsFloat = 0); end; function TBillsIDTree.CreateItem: TsdIDTreeNode; begin Result := TBillsIDTreeNode.Create(Self); end; function TBillsIDTree.DeleteNode(ANode: TsdIDTreeNode): Boolean; var vParent: TsdIDTreeNode; begin vParent := ANode.Parent; Result := inherited DeleteNode(ANode); DoOnReCalcNode(vParent); end; procedure TBillsIDTree.RecodeChildrenB_Code(ANode: TBillsIDTreeNode; AOrgCode, ANewCode: string); var iCount, iTotal: Integer; vChild: TBillsIDTreeNode; begin if (ANewCode = '') or (AOrgCode = '') or (AOrgCode = ANewCode) then Exit; iCount := 0; iTotal := ANode.PosterityCount; vChild := TBillsIDTreeNode(ANode.NextNode); while (iCount < iTotal) and Assigned(vChild) do begin if vChild.Rec.B_Code.AsString <> '' then begin if Pos(AOrgCode+'-', vChild.Rec.B_Code.AsString) = 1 then begin vChild.Rec.B_Code.AsString := StringReplace(vChild.Rec.B_Code.AsString, AOrgCode+'-', ANewCode+'-', []); vChild.Rec.SetBoolValue(vChild.Rec.LockedInfo, False); end; end; vChild := TBillsIDTreeNode(vChild.NextNode); Inc(iCount); end; end; procedure TBillsIDTree.RecodeChildrenCode(ANode: TBillsIDTreeNode; AOrgCode, ANewCode: string); var iCount, iTotal: Integer; vChild: TBillsIDTreeNode; begin if (ANewCode = '') or (AOrgCode = '') or (AOrgCode = ANewCode) then Exit; iCount := 0; iTotal := ANode.PosterityCount; vChild := TBillsIDTreeNode(ANode.NextNode); while (iCount < iTotal) and Assigned(vChild) do begin if vChild.Rec.Code.AsString <> '' then begin if Pos(AOrgCode+'-', vChild.Rec.Code.AsString) = 1 then begin vChild.Rec.Code.AsString := StringReplace(vChild.Rec.Code.AsString, AOrgCode+'-', ANewCode+'-', []); vChild.Rec.SetBoolValue(vChild.Rec.LockedInfo, False); end; end; vChild := TBillsIDTreeNode(vChild.NextNode); Inc(iCount); end; end; { TBillsIDTreeNode } function TBillsIDTreeNode.CanDownLevel: Boolean; begin Result := Inherited CanDownLevel and (Level > 0) and (not Rec.ValueByName('LockedLevel').AsBoolean) and not HasMeasure; if Assigned(PrevSibling) then begin Result := Result and (PrevSibling.HasChildren or not TBillsIDTreeNode(PrevSibling).HasMeasure); end; end; function TBillsIDTreeNode.CanDownMove: Boolean; begin Result := Inherited CanDownMove and (not Rec.ValueByName('LockedLevel').AsBoolean); end; function TBillsIDTreeNode.CanUpLevel: Boolean; var vNextSibling: TsdIDTreeNode; begin Result := Inherited CanUpLevel and (Level > 1) and (not Rec.ValueByName('LockedLevel').AsBoolean) and not HasMeasure; vNextSibling := NextSibling; while Assigned(vNextSibling) and Result do begin Result := Result and not TBillsIDTreeNode(NextSibling).HasMeasure; vNextSibling := vNextSibling.NextSibling; end; end; function TBillsIDTreeNode.CanUpMove: Boolean; begin Result := Inherited CanUpMove and (not Rec.ValueByName('LockedLevel').AsBoolean); end; function TBillsIDTreeNode.CountPriceEnable: Boolean; begin Result := HasCountPrice or (not HasTotalPrice); end; function TBillsIDTreeNode.DownLevel: Boolean; var iOrgParentID: Integer; begin iOrgParentID := ParentID; Result := inherited DownLevel; if not Result then Exit; // 如升级后变为父项,则清空数量、单价 if Assigned(Parent) then begin Parent.Rec.ValueByName('OrgQuantity').AsFloat := 0; Parent.Rec.ValueByName('MisQuantity').AsFloat := 0; Parent.Rec.ValueByName('OthQuantity').AsFloat := 0; Parent.Rec.ValueByName('Quantity').AsFloat := 0; Parent.Rec.ValueByName('Price').AsFloat := 0; end; TBillsIDTree(Owner).DoOnReCalcNode(ParentID); TBillsIDTree(Owner).DoOnReCalcNode(iOrgParentID); end; function TBillsIDTreeNode.GetChapterParent: TBillsIDTreeNode; begin Result := nil; if Self.Level <= 1 then Exit; Result := TBillsIDTreeNode(Self.Parent); while Result.Level > 1 do Result := TBillsIDTreeNode(Result.Parent); end; function TBillsIDTreeNode.GetChapterParentID: Integer; var vNode: TBillsIDTreeNode; begin vNode := GetChapterParent; if Assigned(vNode) then Result := vNode.ID else Result := -1; end; function TBillsIDTreeNode.GetRec: TBillsRecord; begin Result := TBillsRecord(TsdIDTreeNode(Self).Rec); end; function TBillsIDTreeNode.HasCountPrice: Boolean; begin Result := False; if not Assigned(Rec) then Exit; Result := (Rec.Price.AsFloat <> 0) or (Rec.OrgQuantity.AsFloat <> 0) or (Rec.MisQuantity.AsFloat <> 0) or (Rec.OthQuantity.AsFloat <> 0) or (Rec.AddDealQuantity.AsFloat <> 0) or (Rec.AddQcQuantity.AsFloat <> 0) or (Rec.AddPcQuantity.AsFloat <> 0); end; function TBillsIDTreeNode.HasLedger: Boolean; begin Result := False; if not Assigned(Rec) then Exit; Result := (Rec.Price.AsFloat <> 0) or (Rec.Quantity.AsFloat <> 0); end; function TBillsIDTreeNode.HasMeasure: Boolean; begin Result := False; if not Assigned(Rec) then Exit; Result := (Rec.AddDealQuantity.AsFloat <> 0) or (Rec.AddDealTotalPrice.AsFloat <> 0) or (Rec.AddQcQuantity.AsFloat <> 0) or (Rec.AddQcTotalPrice.AsFloat <> 0) or (Rec.AddPcQuantity.AsFloat <> 0) or (Rec.AddPcTotalPrice.AsFloat <> 0); end; function TBillsIDTreeNode.HasTotalPrice: Boolean; begin Result := False; if not Assigned(Rec) then Exit; Result := (Rec.OrgTotalPrice.AsFloat <> 0) or (Rec.MisTotalPrice.AsFloat <> 0) or (Rec.OthTotalPrice.AsFloat <> 0) or (Rec.AddDealTotalPrice.AsFloat <> 0) or (Rec.AddQcTotalPrice.AsFloat <> 0) or (Rec.AddPcTotalPrice.AsFloat <> 0); end; function TBillsIDTreeNode.TotalPriceEnable: Boolean; begin Result := not HasCountPrice; end; function TBillsIDTreeNode.UpLevel: Boolean; var iOrgParentID: Integer; begin iOrgParentID := ParentID; Result := inherited UpLevel; if not Result then Exit; // 如升级后变为父项,则清空数量、单价 if HasChildren then begin Rec.ValueByName('OrgQuantity').AsFloat := 0; Rec.ValueByName('MisQuantity').AsFloat := 0; Rec.ValueByName('OthQuantity').AsFloat := 0; Rec.ValueByName('Quantity').AsFloat := 0; Rec.ValueByName('Price').AsFloat := 0; end; TBillsIDTree(Owner).DoOnReCalcNode(iOrgParentID); TBillsIDTree(Owner).DoOnReCalcNode(ParentID); end; { TEstimateIDTreeNode } function TEstimateIDTreeNode.CanExpand: Boolean; var iChild: Integer; vChild: TsdIDTreeNode; begin Result := True; if HasChildren then for iChild := 0 to ChildCount - 1 do begin vChild := ChildNodes[iChild]; if vChild.Rec.ValueByName('B_Code').AsString <> '' then begin Result := False; Break; end; end; end; { TEstimateIDTree } function TEstimateIDTree.CreateItem: TsdIDTreeNode; begin Result := TEstimateIDTreeNode.Create(Self); end; { TCompileBillsIDTree } procedure TCompileBillsIDTree.DoOnReCalcNode(AID: Integer); begin if (AID <> -1) and Assigned(FOnReCalcNode) then FOnReCalcNode(AID); end; procedure TCompileBillsIDTree.DoOnReCalcNode(ANode: TsdIDTreeNode); begin if Assigned(ANode) then DoOnReCalcNode(ANode.ID); end; { TMeasureBillsIDTree } procedure TMeasureBillsIDTree.DoOnReCalcNode(AID: Integer); begin if Assigned(FCompileTree) then FCompileTree.DoOnReCalcNode(AID); end; function TMeasureBillsIDTree.CreateItem: TsdIDTreeNode; begin Result := TMeasureBillsIDTreeNode.Create(Self); end; procedure TMeasureBillsIDTree.DoOnReCalcNode(ANode: TsdIDTreeNode); begin if Assigned(FCompileTree) then FCompileTree.DoOnReCalcNode(ANode); end; end.