unit rmHaBaiCustomizedDm;

// 内蒙古 哈白项目/国道306定制汇总表 严禁任何其他项目或标表调用该单元
// 包括支表2/3/14/3-1/4-1

interface

uses
  SysUtils, Classes, DB, rmSelectProjectFrm, ProjectData, mDataRecord,
  BillsTree, DBClient;

type
  TDoubleArray = array of Double;
  TStringArray = array of string;

  TGclNode = class
  private
    FProjectCount: Integer;

    FB_Code: string;
    FIndexCode: string;
    FName: string;
    FUnits: string;
    FPrice: Double;
    FCalcType: Integer;

    FQuantity: Double;
    FTotalPrice: Double;

    FCurGatherQuantity: Double;
    FCurGatherTotalPrice: Double;

    FEndGatherQuantity: Double;
    FEndGatherTotalPrice: Double;

    FPreGatherQuantity: Double;
    FPreGatherTotalPrice: Double;

    FP_Quantity: TDoubleArray;
    FP_TotalPrice: TDoubleArray;
    FP_CurGatherQuantity: TDoubleArray;
    FP_CurGatherTotalPrice: TDoubleArray;
    FP_EndGatherQuantity: TDoubleArray;
    FP_EndGatherTotalPrice: TDoubleArray;

    procedure SetB_Code(const Value: string);
    function GetCurPercent: Double;
    function GetEndPercent: Double;
  public
    constructor Create(AProjectCount: Integer);

    procedure Calculate;

    property B_Code: string read FB_Code write SetB_Code;
    property IndexCode: string read FIndexCode;
    property Name: string read FName write FName;
    property Units: string read FUnits write FUnits;
    property Price: Double read FPrice write FPrice;
    property CalcType: Integer read FCalcType write FCalcType;

    property Quantity: Double read FQuantity write FQuantity;
    property TotalPrice: Double read FTotalPrice write FTotalPrice;

    property CurGatherQuantity: Double read FCurGatherQuantity write FCurGatherQuantity;
    property CurGatherTotalPrice: Double read FCurGatherTotalPrice write FCurGatherTotalPrice;

    property EndGatherQuantity: Double read FEndGatherQuantity write FEndGatherQuantity;
    property EndGatherTotalPrice: Double read FEndGatherTotalPrice write FEndGatherTotalPrice;

    property PreGatherQuantity: Double read FPreGatherQuantity write FPreGatherQuantity;
    property PreGatherTotalPrice: Double read FPreGatherTotalPrice write FPreGatherTotalPrice;

    property P_Quantity: TDoubleArray read FP_Quantity write FP_Quantity;
    property P_TotalPrice: TDoubleArray read FP_TotalPrice write FP_TotalPrice;
    property P_CurGatherQuantity: TDoubleArray read FP_CurGatherQuantity write FP_CurGatherQuantity;
    property P_CurGatherTotalPrice: TDoubleArray read FP_CurGatherTotalPrice write FP_CurGatherTotalPrice;
    property P_EndGatherQuantity: TDoubleArray read FP_EndGatherQuantity write FP_EndGatherQuantity;
    property P_EndGatherTotalPrice: TDoubleArray read FP_EndGatherTotalPrice write FP_EndGatherTotalPrice;

    property CurPercent: Double read GetCurPercent;
    property EndPercent: Double read GetEndPercent;
  end;

  TGclChapter = class
  private
    FProjectCount: Integer;
    FGclNodes: TList;

    FChapterID: Integer;
    FChapterBegin: Integer;
    FChapterEnd: Integer;
    FChapterName: string;
    FName: string;

    FTotalPrice: Double;
    FCurGatherTotalPrice: Double;
    FEndGatherTotalPrice: Double;
    FPreGatherTotalPrice: Double;
    FP_TotalPrice: TDoubleArray;
    FP_CurGatherTotalPrice: TDoubleArray;
    FP_EndGatherTotalPrice: TDoubleArray;

    function GetGclNode(AIndex: Integer): TGclNode;
    function GetGclNodeCount: Integer;
    function GetCurPercent: Double;
    function GetEndPercent: Double;
  public
    constructor Create(AChapterID: Integer; const AName: string; AProjectCount: Integer);
    destructor Destroy; override;

    procedure AddGclNode(AGclNode: TGclNode);
    procedure CalculateChapter;

    property ChapterID: Integer read FChapterID;
    property ChapterBegin: Integer read FChapterBegin;
    property ChapterEnd: Integer read FChapterEnd;
    property ChapterName: string read FChapterName;
    property Name: string read FName;

    property TotalPrice: Double read FTotalPrice write FTotalPrice;
    property CurGatherTotalPrice: Double read FCurGatherTotalPrice write FCurGatherTotalPrice;
    property EndGatherTotalPrice: Double read FEndGatherTotalPrice write FEndGatherTotalPrice;
    property PreGatherTotalPrice: Double read FPreGatherTotalPrice write FPreGatherTotalPrice;

    property P_TotalPrice: TDoubleArray read FP_TotalPrice write FP_TotalPrice;
    property P_CurGatherTotalPrice: TDoubleArray read FP_CurGatherTotalPrice write FP_CurGatherTotalPrice;
    property P_EndGatherTotalPrice: TDoubleArray read FP_EndGatherTotalPrice write FP_EndGatherTotalPrice;

    property CurPercent: Double read GetCurPercent;
    property EndPercent: Double read GetEndPercent;

    property GclNodeCount: Integer read GetGclNodeCount;
    property GclNode[AIndex: Integer]: TGclNode read GetGclNode;
  end;

  TGclControl = class
  private
    FProjectCount: Integer;

    FProjectName: TStringArray;
    FGclNodes: TList;
    FGclChapters: TList;
    FGclChapterGather: TGclChapter;
    FOtherGcl: TGclChapter;

    function FindGclNode(ARec: TBillsRecord): TGclNode;
    function NewGclNode(ARec: TBillsRecord): TGclNode;

    function B_CodeToChapter(const AB_Code: string): Integer;
    procedure LinkGclChapter(AGclNode: TGclNode);
    function FindGclChapter(AChapterID: Integer): TGclChapter;

    procedure CalculateChapterGather;

    function GetGclChapterCount: Integer;
    function GetGclChapter(AIndex: Integer): TGclChapter;
  public
    constructor Create(AProjectCount: Integer; AIsHaBai: Boolean);
    destructor Destroy;

    function AddGclNode(ANode: TMeasureBillsIDTreeNode; AProjectIndex: Integer): TGclNode;

    procedure ReCalculateTotalPrice;
    procedure Calculate;

    property GclChapterCount: Integer read GetGclChapterCount;
    property GclChapter[AIndex: Integer]: TGclChapter read GetGclChapter;

    property GclChapterGather: TGclChapter read FGclChapterGather;

    property ProjectName: TStringArray read FProjectName write FProjectName;

    property ProjectCount: Integer read FProjectCount;
  end;

  TPayNode = class
  private
    FName: string;
    FIsMinus: Boolean;

    FCurTotalPrice: Double;
    FEndTotalPrice: Double;
    FPreTotalPrice: Double;
  public
    property Name: string read FName write FName;
    property IsMinus: Boolean read FIsMinus write FisMinus;

    property CurTotalPrice: Double read FCurTotalPrice write FCurTotalPrice;
    property EndTotalPrice: Double read FEndTotalPrice write FEndTotalPrice;
    property PreTotalPrice: Double read FPreTotalPrice write FPreTotalPrice;
  end;

  TDealPayControl = class
  private
    FPlusPayNodes: TList;
    FMinusPayNodes: TList;
    FPlusGather: TPayNode;
    FMinusGather: TPayNode;
    FGatherPayNode: TPayNode;
    FCompletePayNode: TPayNode;

    function FindPlusPayNode(const AName: string): TPayNode;
    function NewPlusPayNode(const AName: string): TPayNode;
    function AddPlusPayNode(const AName: string): TPayNode;

    function FindMinusPayNode(const AName: string): TPayNode;
    function NewMinusPayNode(const AName: string): TPayNode;
    function AddMinusPayNode(const AName: string): TPayNode;

    procedure CalculateGather(AGather: TPayNode; ANodes: TList);

    function GetMinusPayCount: Integer;
    function GetMinusPayNode(AIndex: Integer): TPayNode;
    function GetPlusPayCount: Integer;
    function GetPlusPayNode(AIndex: Integer): TPayNode;
  public
    constructor Create;
    destructor Destroy; override;

    function AddPayNode(const AName: string; AIsMinus: Boolean): TPayNode;

    procedure CalculateAll;

    property PlusPayCount: Integer read GetPlusPayCount;
    property PlusPayNode[AIndex: Integer]: TPayNode read GetPlusPayNode;
    property PlusGather: TPayNode read FPlusGather;

    property MinusPayCount: Integer read GetMinusPayCount;
    property MinusPayNode[AIndex: Integer]:TPayNode read GetMinusPayNode;
    property MinusGather: TPayNode read FMinusGather;

    property GatherPayNode: TPayNode read FGatherPayNode;
    property CompletePayNode: TPayNode read FCompletePayNode;
  end;

  // 分别对应5张定制汇总表的编号，详见文档
  THaBaiGatherType = (hbgt2, hbgt3, hbgt14, hbgt3_1, hbgt4_1, hbgt_CS);
  // CS: Counter Sign 会签

  TrmHaBaiCustomizedData = class(TDataModule)
    cdsCustom2: TClientDataSet;
    cdsCustom2Chapter: TIntegerField;
    cdsCustom2Name: TWideStringField;
    cdsCustom2TotalPrice: TFloatField;
    cdsCustom2CTotalPrice: TFloatField;
    cdsCustom2GTotalPrice: TFloatField;
    cdsCustom2EndGatherTotalPrice: TFloatField;
    cdsCustom2PreGatherTotalPrice: TFloatField;
    cdsCustom2CurGatherTotalPrice: TFloatField;
    cdsCustom2Percent: TFloatField;

    cdsCustom3: TClientDataSet;
    cdsCustom3ChapterID: TIntegerField;
    cdsCustom3InnerPartID: TIntegerField;
    cdsCustom3IndexCode: TStringField;
    cdsCustom3B_Code: TWideStringField;
    cdsCustom3Name: TWideStringField;
    cdsCustom3Units: TWideStringField;
    cdsCustom3Price: TFloatField;
    cdsCustom3Quantity: TFloatField;
    cdsCustom3TotalPrice: TFloatField;
    cdsCustom3PreGatherQuantity: TFloatField;
    cdsCustom3PreGatherTotalPrice: TFloatField;
    cdsCustom3EndGatherQuantity: TFloatField;
    cdsCustom3EndGatherTotalPrice: TFloatField;
    cdsCustom3CurGatherQuantity: TFloatField;
    cdsCustom3CurGatherTotalPrice: TFloatField;
    cdsCustom3Percent: TFloatField;

    cdsCustom14: TClientDataSet;
    cdsCustom14IndexCode: TWideStringField;
    cdsCustom14B_Code: TWideStringField;
    cdsCustom14Name: TWideStringField;
    cdsCustom14Units: TWideStringField;
    cdsCustom14Price: TFloatField;
    cdsCustom14Quantity: TFloatField;
    cdsCustom14TotalPrice: TFloatField;
    cdsCustom14CertificateCode: TWideStringField;

    cdsCustomProj: TClientDataSet;
    cdsCustomProjProjectID: TIntegerField;
    cdsCustomProjProjectName: TWideStringField;
    cdsCustomProjChapterID: TIntegerField;
    cdsCustomProjInnerPartID: TIntegerField;
    cdsCustomProjIndexCode: TWideStringField;
    cdsCustomProjB_Code: TWideStringField;
    cdsCustomProjName: TWideStringField;
    cdsCustomProjUnits: TWideStringField;
    cdsCustomProjPrice: TFloatField;
    cdsCustomProjQuantity: TFloatField;
    cdsCustomProjTotalPrice: TFloatField;
    cdsCustomProjCurGatherQuantity: TFloatField;
    cdsCustomProjCurGatherTotalPrice: TFloatField;
    cdsCustomProjEndGatherQuantity: TFloatField;
    cdsCustomProjEndGatherTotalPrice: TFloatField;
    cdsCustomProjP_CurGatherQuantity: TFloatField;
    cdsCustomProjP_CurGatherTotalPrice: TFloatField;
    cdsCustomProjP_EndGatherQuantity: TFloatField;
    cdsCustomProjP_EndGatherTotalPrice: TFloatField;
    cdsCustomProjCurPercent: TFloatField;
    cdsCustomProjEndPercent: TFloatField;
    cdsCustomProjSerialNo: TIntegerField;

    // 会签表
    // 流水
    cdsCustomCS_1: TClientDataSet;
    cdsCustomCS_1PulsPayName: TWideStringField;
    cdsCustomCS_1PulsPayTotalPrice: TFloatField;
    cdsCustomCS_1MinusPayName: TWideStringField;
    cdsCustomCS_1MinusPayTotalPrice: TFloatField;
    // 账单
    cdsCustomCS_2: TClientDataSet;
    cdsCustomCS_2DealTotalPrice: TFloatField;
    cdsCustomCS_2EndCompleteTotalPrice: TFloatField;
    cdsCustomCS_2PreCompleteTotalPrice: TFloatField;
    cdsCustomCS_2CurPayTotalPrice: TFloatField;
  private
    FhbGatherType: THaBaiGatherType;
    FProjectData: TProjectData;
    FProjectName: string;
    FGclControl: TGclControl;
    FDealPayControl: TDealPayControl;
    FDealTotalPrice: Double;

    procedure BeforeGather(AProjectCount: Integer; AIsHaBai: Boolean);
    procedure AfterGather;

    procedure OpenProjectData(AProject: TSelectProject);
    procedure FreeProjectData;

    procedure GatherProject(AProject: TSelectProject; AProjectIndex: Integer);

    procedure FilterGcl(AProjectIndex: Integer);
    procedure FilterDealPay;
    procedure WriteFlowData;

    procedure WriteReport2;
    procedure WriteReport3;
    procedure WriteReport3_1;
    procedure WriteReport4_1;
    procedure WriteReportCounterSign;

    procedure WriteData;
  public
    function AssignData(AProjects: TList; AhbGatherType: THaBaiGatherType; AReCalc: Boolean): TDataSet;
    function AssignAssistantData(AhbGatherType: THaBaiGatherType): TDataSet;

    property hbGatherType: THaBaiGatherType read FhbGatherType;
  end;

implementation

uses
  UtilMethods, ZhAPI, BillsCompileDm, sdDB, Globals, Math, BillsMeasureDm,
  ZJJLDm, BillsDm;

{$R *.dfm}

{ TrmHaBaiCustomizedData }

function TrmHaBaiCustomizedData.AssignData(AProjects: TList;
  AhbGatherType: THaBaiGatherType; AReCalc: Boolean): TDataSet;
var
  iProject: Integer;
begin
  FhbGatherType := AhbGatherType;
  BeforeGather(AProjects.Count, AReCalc);
  try
    for iProject := 0 to AProjects.Count - 1 do
      GatherProject(TSelectProject(AProjects.Items[iProject]), iProject);
    if AReCalc then
      FGclControl.ReCalculateTotalPrice;
    FGclControl.Calculate;
    WriteData;
  finally
    AfterGather;
    case FhbGatherType of
      hbgt2: Result := cdsCustom2;
      hbgt3: Result := cdsCustom3;
      hbgt14: Result := cdsCustom14;
      hbgt3_1, hbgt4_1: Result := cdsCustomProj;
      hbgt_CS: Result := cdsCustomCS_1;
    end;
  end;
end;

procedure TrmHaBaiCustomizedData.BeforeGather(AProjectCount: Integer; AIsHaBai: Boolean);
begin
  cdsCustom2.DisableControls;
  cdsCustom2.Active := True;
  cdsCustom2.EmptyDataSet;

  cdsCustom3.DisableControls;
  cdsCustom3.Active := True;
  cdsCustom3.EmptyDataSet;

  cdsCustom14.DisableControls;
  cdsCustom14.Active := True;
  cdsCustom14.EmptyDataSet;

  cdsCustomProj.DisableControls;
  cdsCustomProj.Active := True;
  cdsCustomProj.EmptyDataSet;

  cdsCustomCS_1.DisableControls;
  cdsCustomCS_1.Active := True;
  cdsCustomCS_1.EmptyDataSet;

  cdsCustomCS_2.DisableControls;
  cdsCustomCS_2.Active := True;
  cdsCustomCS_2.EmptyDataSet;

  FGclControl := TGclControl.Create(AProjectCount, AIsHaBai);
  FDealPayControl := TDealPayControl.Create;
  FDealTotalPrice := 0;
end;

procedure TrmHaBaiCustomizedData.AfterGather;
begin
  FDealPayControl.Free;
  FGclControl.Free;

  cdsCustomCS_2.EnableControls;
  cdsCustomCS_1.EnableControls;
  cdsCustomProj.EnableControls;
  cdsCustom14.EnableControls;
  cdsCustom3.EnableControls;
  cdsCustom2.EnableControls;
end;

procedure TrmHaBaiCustomizedData.FreeProjectData;
begin
  if not Assigned(OpenProjectManager.FindProjectData(FProjectData.ProjectID)) then
    FProjectData.Free;
end;

procedure TrmHaBaiCustomizedData.OpenProjectData(AProject: TSelectProject);
var
  Rec: TsdDataRecord;
begin
  FProjectData := OpenProjectManager.FindProjectData(AProject.ProjectID);
  Rec := ProjectManager.sddProjectsInfo.FindKey('idxID', AProject.ProjectID);
  if not Assigned(FProjectData) then
  begin
    FProjectData := TProjectData.Create;
    FProjectData.OpenForReport3(GetMyProjectsFilePath + Rec.ValueByName('FileName').AsString);
  end;
  FProjectName := Rec.ValueByName('Name').AsString;
end;

procedure TrmHaBaiCustomizedData.GatherProject(AProject: TSelectProject;
  AProjectIndex: Integer);
begin
  OpenProjectData(AProject);
  try
    FGclControl.ProjectName[AProjectIndex] := FProjectName;
    if FhbGatherType in [hbgt2, hbgt3, hbgt3_1, hbgt4_1] then
      FilterGcl(AProjectIndex);
    if FhbGatherType in [hbgt2, hbgt_CS] then
      FilterDealPay;
    if FhbGatherType = hbgt14 then
      WriteFlowData;
    if FhbGatherType = hbgt_CS then
      FDealTotalPrice := FDealTotalPrice + FProjectData.BillsData.Settlement[0];
  finally
    FreeProjectData;
  end;
end;

procedure TrmHaBaiCustomizedData.FilterGcl(AProjectIndex: Integer);
var
  i: Integer;
  vNode: TMeasureBillsIDTreeNode;
  GclNode: TGclNode;
begin
  with FProjectData.BillsMeasureData do
  begin
    for i := 0 to BillsMeasureTree.Count - 1 do
    begin
      vNode := TMeasureBillsIDTreeNode(BillsMeasureTree.Items[i]);
      if not vNode.HasChildren and (vNode.Rec.B_Code.AsString <> '') then
        GclNode := FGclControl.AddGclNode(vNode, AProjectIndex);
    end;
  end;
end;

procedure TrmHaBaiCustomizedData.FilterDealPay;
var
  sCurField, sPreField, sEndField: string;

  procedure GatherCommonDealPayData;
  var
    iRec: Integer;
    Rec, StageRec: TsdDataRecord;
    DealPay: TPayNode;
  begin
    with FProjectData.DealPaymentData do
    begin
      for iRec := 0 to sddDealPayment.RecordCount - 1 do
      begin
        Rec := sddDealPayment.Records[iRec];
        if SameText(Rec.ValueByName('Name').AsString, '本期完成计量') or
           SameText(Rec.ValueByName('Name').AsString, '本期应付') or
           SameText(Rec.ValueByName('Name').AsString, '本期实付') then
          Continue;
        if FProjectData.PhaseData.Active then
          StageRec := FProjectData.PhaseData.PhasePayData.PayRecord(Rec.ValueByName('ID').AsInteger)
        else
          StageRec := nil;
        DealPay := FDealPayControl.AddPayNode(Rec.ValueByName('Name').AsString, Rec.ValueByName('IsMinus').AsBoolean);
        if Assigned(StageRec) then
        begin
          DealPay.CurTotalPrice := DealPay.CurTotalPrice + StageRec.ValueByName(sCurField).AsFloat;
          DealPay.PreTotalPrice := DealPay.PreTotalPrice + StageRec.ValueByName(sPreField).AsFloat;
          DealPay.EndTotalPrice := DealPay.EndTotalPrice + StageRec.ValueByName(sEndField).AsFloat;
        end;
      end;
    end;
  end;

  procedure GatherCompletePayData;
  var
    Rec, StageRec: TsdDataRecord;
  begin
    Rec := FProjectData.DealPaymentData.DealPayRecord('本期完成计量');
    if FProjectData.PhaseData.Active then
      StageRec := FProjectData.PhaseData.PhasePayData.PayRecord(Rec.ValueByName('ID').AsInteger)
    else
      StageRec := nil;
    if not Assigned(StageRec) then Exit;

    with FDealPayControl.CompletePayNode do
    begin
      CurTotalPrice := CurTotalPrice + StageRec.ValueByName(sCurField).AsFloat;
      PreTotalPrice := PreTotalPrice + StageRec.ValueByName(sPreField).AsFloat;
      EndTotalPrice := EndTotalPrice + StageRec.ValueByName(sEndField).AsFloat;
    end;
  end;

  procedure GatherPayData;
  var
    Rec, StageRec: TsdDataRecord;
  begin
    Rec := FProjectData.DealPaymentData.DealPayRecord('本期应付');
    if FProjectData.PhaseData.Active then
      StageRec := FProjectData.PhaseData.PhasePayData.PayRecord(Rec.ValueByName('ID').AsInteger)
    else
      StageRec := nil;

    if not Assigned(StageRec) then Exit;

    with FDealPayControl.GatherPayNode do
    begin
      CurTotalPrice := CurTotalPrice + StageRec.ValueByName(sCurField).AsFloat;
      PreTotalPrice := PreTotalPrice + StageRec.ValueByName(sPreField).AsFloat;
      EndTotalPrice := EndTotalPrice + StageRec.ValueByName(sEndField).AsFloat;
    end;
  end;

begin
  sCurField := 'TotalPrice' + IntToStr(FProjectData.PhaseData.AuditCount);
  sPreField := 'PreTotalPrice' + IntToStr(FProjectData.PhaseData.AuditCount);
  sEndField := 'EndTotalPrice' + IntToStr(FProjectData.PhaseData.AuditCount);
  GatherCommonDealPayData;
  GatherCompletePayData;
  GatherPayData;
  FDealPayControl.CalculateAll;
end;

procedure TrmHaBaiCustomizedData.WriteData;
begin
  case FhbGatherType of
    hbgt2: WriteReport2;
    hbgt3: WriteReport3;
    hbgt3_1: WriteReport3_1;
    hbgt4_1: WriteReport4_1;
    hbgt_CS: WriteReportCounterSign;
  end;
end;

procedure TrmHaBaiCustomizedData.WriteReport2;

  procedure WriteGclChapter(AGclChapter: TGclChapter; const AName: string = '');
  begin
    cdsCustom2.Append;
    if AGclChapter.ChapterBegin > 0 then
      cdsCustom2Chapter.AsInteger := AGclChapter.ChapterBegin;
    if AName = '' then
      cdsCustom2Name.AsString := AGclChapter.Name
    else
      cdsCustom2Name.AsString := AName;
    cdsCustom2TotalPrice.AsFloat := AGclChapter.TotalPrice;
    cdsCustom2GTotalPrice.AsFloat := AGclChapter.TotalPrice;
    cdsCustom2EndGatherTotalPrice.AsFloat := AGclChapter.EndGatherTotalPrice;
    cdsCustom2PreGatherTotalPrice.AsFloat := AGclChapter.PreGatherTotalPrice;
    cdsCustom2CurGatherTotalPrice.AsFloat := AGclChapter.CurGatherTotalPrice;
    cdsCustom2Percent.AsFloat := AGclChapter.EndPercent;
    cdsCustom2.Post;
  end;

  procedure WriteBlankRecord(const AName: string);
  begin
    cdsCustom2.Append;
    cdsCustom2Name.AsString := AName;
    cdsCustom2.Post;
  end;

  procedure WritePayNode(APayNode: TPayNode; const AName: string = '');
  begin
    cdsCustom2.Append;
    if AName = '' then
      cdsCustom2Name.AsString := APayNode.Name
    else
      cdsCustom2Name.AsString := AName;
    cdsCustom2EndGatherTotalPrice.AsFloat := APayNode.EndTotalPrice;
    cdsCustom2PreGatherTotalPrice.AsFloat := APayNode.PreTotalPrice;
    cdsCustom2CurGatherTotalPrice.AsFloat := APayNode.CurTotalPrice;
    cdsCustom2.Post;
  end;

  procedure WriteSpecialRecord;
  begin
    cdsCustom2.Append;
    cdsCustom2Name.AsString := '合  计';
    cdsCustom2EndGatherTotalPrice.AsFloat := FGclControl.GclChapterGather.EndGatherTotalPrice + FDealPayControl.PlusGather.EndTotalPrice;
    cdsCustom2PreGatherTotalPrice.AsFloat := FGclControl.GclChapterGather.PreGatherTotalPrice + FDealPayControl.PlusGather.PreTotalPrice;
    cdsCustom2CurGatherTotalPrice.AsFloat := FGclControl.GclChapterGather.CurGatherTotalPrice + FDealPayControl.PlusGather.CurTotalPrice;
    cdsCustom2.Post;
  end;

  procedure WriteMentalNode;
  begin
    cdsCustom2.Append;
    cdsCustom2Name.AsString := '支  付';
    cdsCustom2EndGatherTotalPrice.AsFloat := FGclControl.GclChapterGather.EndGatherTotalPrice + FDealPayControl.PlusGather.EndTotalPrice
        - FDealPayControl.MinusGather.EndTotalPrice;
    cdsCustom2PreGatherTotalPrice.AsFloat := FGclControl.GclChapterGather.PreGatherTotalPrice + FDealPayControl.PlusGather.PreTotalPrice
        - FDealPayControl.MinusGather.PreTotalPrice;
    cdsCustom2CurGatherTotalPrice.AsFloat := FGclControl.GclChapterGather.CurGatherTotalPrice + FDealPayControl.PlusGather.CurTotalPrice
        - FDealPayControl.MinusGather.CurTotalPrice;
    cdsCustom2.Post;
  end;

var
  iIndex: Integer;
begin
  for iIndex := 0 to FGclControl.GclChapterCount - 1 do
    WriteGclChapter(FGclControl.GclChapter[iIndex]);
  WriteGclChapter(FGclControl.GclChapterGather);
  WriteGclChapter(FGclControl.GclChapterGather, '小  计');
  WriteBlankRecord('价格调整');
  WriteBlankRecord('违约罚金');
  WriteBlankRecord('迟付款利息');
  for iIndex := 0 to FDealPayControl.PlusPayCount - 1 do
    WritePayNode(FDealPayControl.PlusPayNode[iIndex]);
  WriteSpecialRecord;
  for iIndex := 0 to FDealPayControl.MinusPayCount - 1 do
    WritePayNode(FDealPayControl.MinusPayNode[iIndex]);
  //WritePayNode(FDealPayControl.GatherPayNode, '支  付');
  // 神经病有毛病
  WriteMentalNode;
end;

procedure TrmHaBaiCustomizedData.WriteReport3;

  procedure WriteChapterName(AGclChapter: TGclChapter);
  begin
    cdsCustom3.Append;
    cdsCustom3ChapterID.AsInteger := AGclChapter.ChapterID;
    cdsCustom3InnerPartID.AsInteger := 1;
    cdsCustom3B_Code.AsString := AGclChapter.ChapterName;
    cdsCustom3Name.AsString := AGclChapter.Name;
    cdsCustom3.Post;
  end;

  procedure WriteGclNodeData(AGclNode: TGclNode; AChapterID: Integer);
  begin
    cdsCustom3.Append;
    cdsCustom3ChapterID.AsInteger := AChapterID;
    cdsCustom3InnerPartID.AsInteger := 2;
    cdsCustom3IndexCode.AsString := AGclNode.IndexCode;
    cdsCustom3B_Code.AsString := AGclNode.B_Code;
    cdsCustom3Name.AsString := AGclNode.Name;
    cdsCustom3Units.AsString := AGclNode.Units;
    cdsCustom3Price.AsFloat := AGclNode.Price;
    cdsCustom3Quantity.AsFloat := AGclNode.Quantity;
    cdsCustom3TotalPrice.AsFloat := AGclNode.TotalPrice;
    cdsCustom3CurGatherQuantity.AsFloat := AGclNode.CurGatherQuantity;
    cdsCustom3CurGatherTotalPrice.AsFloat := AGclNode.CurGatherTotalPrice;
    cdsCustom3EndGatherQuantity.AsFloat := AGclNode.EndGatherQuantity;
    cdsCustom3EndGatherTotalPrice.AsFloat := AGclNode.EndGatherTotalPrice;
    cdsCustom3PreGatherQuantity.AsFloat := AGclNode.PreGatherQuantity;
    cdsCustom3PreGatherTotalPrice.AsFloat := AGclNode.PreGatherTotalPrice;
    cdsCustom3Percent.AsFloat := AGclNode.EndPercent;
    cdsCustom3.Post;
  end;

  procedure WriteChapterGather(AGclChapter: TGclChapter; const AName: string = '');
  begin
    cdsCustom3.Append;
    cdsCustom3ChapterID.AsInteger := AGclChapter.ChapterID;
    cdsCustom3InnerPartID.AsInteger := 3;
    if AName = '' then
      cdsCustom3Name.AsString := AGclChapter.Name
    else
      cdsCustom3Name.AsString := AName;
    cdsCustom3TotalPrice.AsFloat := AGclChapter.TotalPrice;
    cdsCustom3CurGatherTotalPrice.AsFloat := AGclChapter.CurGatherTotalPrice;
    cdsCustom3EndGatherTotalPrice.AsFloat := AGclChapter.EndGatherTotalPrice;
    cdsCustom3PreGatherTotalPrice.AsFloat := AGclChapter.PreGatherTotalPrice;
    cdsCustom3Percent.AsFloat := AGclChapter.EndPercent;
    cdsCustom3.Post;
  end;

  procedure WriteGclChapterData(AGclChapter: TGclChapter);
  var
    iGcl: Integer;
  begin
    if AGclChapter.GclNodeCount = 0 then Exit;

    WriteChapterName(AGclChapter);
    for iGcl := 0 to AGclChapter.GclNodeCount - 1 do
      WriteGclNodeData(AGclChapter.GclNode[iGcl], AGclChapter.ChapterID);
    WriteChapterGather(AGclChapter, Format('%s  小计', [AGclChapter.ChapterName]));
  end;

var
  iIndex: Integer;
begin
  for iIndex := 0 to FGclControl.GclChapterCount - 1 do
    WriteGclChapterData(FGclControl.GclChapter[iIndex]);
  WriteChapterGather(FGclControl.GclChapterGather, '第100章～第900章  合计');
end;

procedure TrmHaBaiCustomizedData.WriteReport3_1;
var
  iProject, iChapter: Integer;
  sProjectName: string;

  procedure WriteChapterName(AGclChapter: TGclChapter);
  begin
    cdsCustomProj.Append;
    cdsCustomProjProjectID.AsInteger := iProject;
    cdsCustomProjProjectName.AsString := sProjectName;
    cdsCustomProjChapterID.AsInteger := AGclChapter.ChapterID;
    cdsCustomProjInnerPartID.AsInteger := 1;
    cdsCustomProjB_Code.AsString := AGclChapter.ChapterName;
    cdsCustomProjName.AsString := AGclChapter.Name;
    cdsCustomProj.Post;
  end;

  procedure WriteGclNodeData(AGclNode: TGclNode; AChapterID: Integer);
  begin
    cdsCustomProj.Append;
    cdsCustomProjProjectID.AsInteger := iProject;
    cdsCustomProjProjectName.AsString := sProjectName;
    cdsCustomProjChapterID.AsInteger := AChapterID;
    cdsCustomProjInnerPartID.AsInteger := 2;
    cdsCustomProjIndexCode.AsString := AGclNode.IndexCode;
    cdsCustomProjB_Code.AsString := AGclNode.B_Code;
    cdsCustomProjName.AsString := AGclNode.Name;
    cdsCustomProjUnits.AsString := AGclNode.Units;
    cdsCustomProjPrice.AsFloat := AGclNode.Price;
    cdsCustomProjQuantity.AsFloat := AGclNode.Quantity;
    cdsCustomProjTotalPrice.AsFloat := AGclNode.TotalPrice;
    cdsCustomProjCurGatherQuantity.AsFloat := AGclNode.CurGatherQuantity;
    cdsCustomProjCurGatherTotalPrice.AsFloat := AGclNode.CurGatherTotalPrice;
    cdsCustomProjEndGatherQuantity.AsFloat := AGclNode.EndGatherQuantity;
    cdsCustomProjEndGatherTotalPrice.AsFloat := AGclNode.EndGatherTotalPrice;
    cdsCustomProjP_CurGatherQuantity.AsFloat := AGclNode.P_CurGatherQuantity[iProject];
    cdsCustomProjP_CurGatherTotalPrice.AsFloat := AGclNode.P_CurGatherTotalPrice[iProject];
    cdsCustomProjP_EndGatherQuantity.AsFloat := AGclNode.P_EndGatherQuantity[iProject];
    cdsCustomProjP_EndGatherTotalPrice.AsFloat := AGclNode.P_EndGatherTotalPrice[iProject];
    cdsCustomProjCurPercent.AsFloat := AGclNode.CurPercent;
    cdsCustomProjEndPercent.AsFloat := AGclNode.EndPercent;
    cdsCustomProj.Post;
  end;

  procedure WriteChapterGather(AGclChapter: TGclChapter; const AName: string = '');
  begin
    cdsCustomProj.Append;
    cdsCustomProjProjectID.AsInteger := iProject;
    cdsCustomProjProjectName.AsString := sProjectName;
    cdsCustomProjChapterID.AsInteger := AGclChapter.ChapterID;
    cdsCustomProjInnerPartID.AsInteger := 3;
    if AName = '' then
      cdsCustomProjName.AsString := AGclChapter.Name
    else
      cdsCustomProjName.AsString := AName;
    cdsCustomProjTotalPrice.AsFloat := AGclChapter.TotalPrice;
    cdsCustomProjCurGatherTotalPrice.AsFloat := AGclChapter.CurGatherTotalPrice;
    cdsCustomProjEndGatherTotalPrice.AsFloat := AGclChapter.EndGatherTotalPrice;
    cdsCustomProjP_CurGatherTotalPrice.AsFloat := AGclChapter.P_CurGatherTotalPrice[iProject];
    cdsCustomProjP_EndGatherTotalPrice.AsFloat := AGclChapter.P_EndGatherTotalPrice[iProject];
    cdsCustomProjCurPercent.AsFloat := AGclChapter.CurPercent;
    cdsCustomProjEndPercent.AsFloat := AGclChapter.EndPercent;
    cdsCustomProj.Post;
  end;

  procedure WriteGclChapterData(AGclChapter: TGclChapter);
  var
    iGcl: Integer;
  begin
    if AGclChapter.GclNodeCount = 0 then Exit;

    WriteChapterName(AGclChapter);
    for iGcl := 0 to AGclChapter.GclNodeCount - 1 do
      WriteGclNodeData(AGclChapter.GclNode[iGcl], AGclChapter.ChapterID);
    WriteChapterGather(AGclChapter, Format('%s  小计', [AGclChapter.ChapterName]));
  end;

begin
  for iProject := 0 to FGclControl.ProjectCount - 1 do
  begin
    sProjectName := FGclControl.ProjectName[iProject];
    for iChapter := 0 to FGclControl.GclChapterCount - 1 do
      WriteGclChapterData(FGclControl.GclChapter[iChapter]);
    WriteChapterGather(FGclControl.GclChapterGather, '第100章至第900章  合计');
  end;
end;

procedure TrmHaBaiCustomizedData.WriteReport4_1;
var
  iProject, iChapter, iSerial: Integer;
  sProjectName: string;

  procedure WriteGclNodeData(AGclNode: TGclNode; AChapterID: Integer);
  begin
    cdsCustomProj.Append;
    cdsCustomProjProjectID.AsInteger := iProject;
    cdsCustomProjProjectName.AsString := sProjectName;
    cdsCustomProjChapterID.AsInteger := AChapterID;
    cdsCustomProjInnerPartID.AsInteger := 2;
    cdsCustomProjIndexCode.AsString := AGclNode.IndexCode;
    cdsCustomProjB_Code.AsString := AGclNode.B_Code;
    cdsCustomProjName.AsString := AGclNode.Name;
    cdsCustomProjUnits.AsString := AGclNode.Units;
    cdsCustomProjPrice.AsFloat := AGclNode.Price;
    cdsCustomProjQuantity.AsFloat := AGclNode.Quantity;
    cdsCustomProjTotalPrice.AsFloat := AGclNode.TotalPrice;
    cdsCustomProjCurGatherQuantity.AsFloat := AGclNode.CurGatherQuantity;
    cdsCustomProjCurGatherTotalPrice.AsFloat := AGclNode.CurGatherTotalPrice;
    cdsCustomProjEndGatherQuantity.AsFloat := AGclNode.EndGatherQuantity;
    cdsCustomProjEndGatherTotalPrice.AsFloat := AGclNode.EndGatherTotalPrice;
    cdsCustomProjP_CurGatherQuantity.AsFloat := AGclNode.P_CurGatherQuantity[iProject];
    cdsCustomProjP_CurGatherTotalPrice.AsFloat := AGclNode.P_CurGatherTotalPrice[iProject];
    cdsCustomProjP_EndGatherQuantity.AsFloat := AGclNode.P_EndGatherQuantity[iProject];
    cdsCustomProjP_EndGatherTotalPrice.AsFloat := AGclNode.P_EndGatherTotalPrice[iProject];
    cdsCustomProjCurPercent.AsFloat := AGclNode.CurPercent;
    cdsCustomProjEndPercent.AsFloat := AGclNode.EndPercent;
    cdsCustomProj.Post;
  end;

  procedure WriteGclChapterData(AGclChapter: TGclChapter);
  var
    iGcl: Integer;
  begin
    if AGclChapter.GclNodeCount = 0 then Exit;

    for iGcl := 0 to AGclChapter.GclNodeCount - 1 do
      WriteGclNodeData(AGclChapter.GclNode[iGcl], AGclChapter.ChapterID);
  end;

  procedure WriteChapterGather(AGclChapter: TGclChapter; const AName: string = '');
  begin
    cdsCustomProj.Append;
    cdsCustomProjProjectID.AsInteger := iProject;
    cdsCustomProjProjectName.AsString := sProjectName;
    cdsCustomProjChapterID.AsInteger := AGclChapter.ChapterID;
    cdsCustomProjInnerPartID.AsInteger := 3;
    if AName = '' then
      cdsCustomProjName.AsString := AGclChapter.Name
    else
      cdsCustomProjName.AsString := AName;
    cdsCustomProjTotalPrice.AsFloat := AGclChapter.TotalPrice;
    cdsCustomProjCurGatherTotalPrice.AsFloat := AGclChapter.CurGatherTotalPrice;
    cdsCustomProjEndGatherTotalPrice.AsFloat := AGclChapter.EndGatherTotalPrice;
    cdsCustomProjP_CurGatherTotalPrice.AsFloat := AGclChapter.P_CurGatherTotalPrice[iProject];
    cdsCustomProjP_EndGatherTotalPrice.AsFloat := AGclChapter.P_EndGatherTotalPrice[iProject];
    cdsCustomProjCurPercent.AsFloat := AGclChapter.CurPercent;
    cdsCustomProjEndPercent.AsFloat := AGclChapter.EndPercent;
    cdsCustomProj.Post;
  end;

  procedure ResortSerialNo;
  var
    iSerialNo, iProject: Integer;
  begin
    iSerialNo := 1;
    cdsCustomProj.First;
    iProject := cdsCustomProjProjectID.AsInteger;
    while not cdsCustomProj.Eof do
    begin
      if iProject <> cdsCustomProjProjectID.AsInteger then
      begin
        iProject := cdsCustomProjProjectID.AsInteger;
        iSerialNo := 1;
      end;
      cdsCustomProj.Edit;
      cdsCustomProjSerialNo.AsInteger := iSerialNo;
      cdsCustomProj.Post;
      Inc(iSerialNo);
      cdsCustomProj.Next;
    end;
  end;

begin
  for iProject := 0 to FGclControl.ProjectCount - 1 do
  begin
    sProjectName := FGclControl.ProjectName[iProject];
    for iChapter := 0 to FGclControl.GclChapterCount - 1 do
      WriteGclChapterData(FGclControl.GclChapter[iChapter]);
    WriteChapterGather(FGclControl.GclChapterGather, '第100章至第900章  合计');
  end;
  ResortSerialNo;
end;

procedure TrmHaBaiCustomizedData.WriteFlowData;

  procedure AddNodeData(ANode: TMeasureBillsIDTreeNode);
  var
    vRec: TsdDataRecord;
  begin
    cdsCustom14.Append;
    cdsCustom14IndexCode.AsString := ANode.Rec.IndexCode.AsString;
    cdsCustom14B_Code.AsString := ANode.Rec.B_Code.AsString;
    cdsCustom14Name.AsString := ANode.Rec.Name.AsString;
    cdsCustom14Units.AsString := ANode.Rec.Units.AsString;
    cdsCustom14Price.AsFloat := ANode.Rec.Price.AsFloat;
    cdsCustom14Quantity.AsFloat := ANode.StageRec.GatherQuantity.AsFloat;
    cdsCustom14TotalPrice.AsFloat := ANode.StageRec.GatherTotalPrice.AsFloat;
    with FProjectData.PhaseData.ZJJLData do
    begin
      vRec := sddZJJL.FindKey('idxBillsID', ANode.ID);
      if Assigned(vRec) then
        cdsCustom14CertificateCode.AsString := vRec.ValueByName('CertificateCode').AsString;
    end;
    cdsCustom14.Post;
  end;

var
  iIndex: Integer;
  vNode: TMeasureBillsIDTreeNode;
begin
  for iIndex := 0 to FProjectData.BillsMeasureData.BillsMeasureTree.Count - 1 do
  begin
    vNode := TMeasureBillsIDTreeNode(FProjectData.BillsMeasureData.BillsMeasureTree.Items[iIndex]);
    if (not vNode.HasChildren) and (vNode.Rec.B_Code.AsString <> '') and
        Assigned(vNode.StageRec) and (vNode.StageRec.GatherTotalPrice.AsFloat <> 0) then
      AddNodeData(vNode);
  end;
end;

function TrmHaBaiCustomizedData.AssignAssistantData(
  AhbGatherType: THaBaiGatherType): TDataSet;
begin
  Result := nil;
  if (AhbGatherType = hbgt_CS) and (FhbGatherType = hbgt_CS) then
    Result := cdsCustomCS_2;
end;

procedure TrmHaBaiCustomizedData.WriteReportCounterSign;

  procedure WriteCounterSign1;
  var
    i: Integer;
    PayNode: TPayNode;
  begin
    cdsCustomCS_1.Append;
    cdsCustomCS_1PulsPayName.AsString := '本期完成金额';
    cdsCustomCS_1PulsPayTotalPrice.AsFloat := FDealPayControl.CompletePayNode.CurTotalPrice;
    cdsCustomCS_1.Post;

    for i := 0 to FDealPayControl.PlusPayCount - 1 do
    begin
      PayNode := FDealPayControl.PlusPayNode[i];
      cdsCustomCS_1.Append;
      cdsCustomCS_1PulsPayName.AsString := PayNode.Name;
      cdsCustomCS_1PulsPayTotalPrice.AsFloat := PayNode.CurTotalPrice;
      cdsCustomCS_1.Post;
    end;

    cdsCustomCS_1.Append;
    cdsCustomCS_1PulsPayName.AsString := '迟付款利息';
    cdsCustomCS_1.Post;

    cdsCustomCS_1.First;
    for i := 0 to FDealPayControl.MinusPayCount - 1 do
    begin
      PayNode := FDealPayControl.MinusPayNode[i];
      if cdsCustomCS_1.Eof then
        cdsCustomCS_1.Append
      else
        cdsCustomCS_1.Edit;
      cdsCustomCS_1MinusPayName.AsString := PayNode.Name;
      cdsCustomCS_1MinusPayTotalPrice.AsFloat := PayNode.CurTotalPrice;
      cdsCustomCS_1.Post;
      cdsCustomCS_1.Next;
    end;
  end;

  procedure WriteCounterSign2;
  begin
    cdsCustomCS_2.Append;
    cdsCustomCS_2DealTotalPrice.AsFloat := FDealTotalPrice;
    cdsCustomCS_2EndCompleteTotalPrice.AsFloat := FDealPayControl.CompletePayNode.EndTotalPrice;
    cdsCustomCS_2PreCompleteTotalPrice.AsFloat := FDealPayControl.CompletePayNode.PreTotalPrice;
    cdsCustomCS_2CurPayTotalPrice.AsFloat := FDealPayControl.GatherPayNode.CurTotalPrice;
    cdsCustomCS_2.Post;
  end;

begin
  WriteCounterSign1;
  WriteCounterSign2;
end;

{ TGclNode }

procedure TGclNode.Calculate;
var
  i: Integer;
begin
  // 金额模式下不重算
  if CalcType <> 0 then Exit;

  FTotalPrice := FPrice * FQuantity;
  FCurGatherTotalPrice := FPrice * FCurGatherQuantity;
  FEndGatherTotalPrice := FPrice * FEndGatherQuantity;
  FPreGatherTotalPrice := FPrice * FPreGatherQuantity;
  for i := 0 to FProjectCount - 1 do
  begin
    FP_TotalPrice[i] := FPrice * FP_Quantity[i];
    FP_CurGatherTotalPrice[i] := FPrice * FP_CurGatherQuantity[i];
    FP_EndGatherTotalPrice[i] := FPrice * FP_EndGatherQuantity[i];
  end;
end;

constructor TGclNode.Create(AProjectCount: Integer);
begin
  FProjectCount := AProjectCount;
  SetLength(FP_Quantity, FProjectCount);
  SetLength(FP_TotalPrice, FProjectCount);
  SetLength(FP_CurGatherQuantity, FProjectCount);
  SetLength(FP_CurGatherTotalPrice, FProjectCount);
  SetLength(FP_EndGatherQuantity, FProjectCount);
  SetLength(FP_EndGatherTotalPrice, FProjectCount);
end;

function TGclNode.GetCurPercent: Double;
begin
  if TotalPrice <> 0 then
    Result := CurGatherTotalPrice/TotalPrice*100
  else
    Result := 0;
end;

function TGclNode.GetEndPercent: Double;
begin
  if TotalPrice <> 0 then
    Result := EndGatherTotalPrice/TotalPrice*100
  else
    Result := 0;
end;

procedure TGclNode.SetB_Code(const Value: string);
begin
  FB_Code := Value;
  FIndexCode := B_CodeToIndexCode(FB_Code);
end;

{ TGclControl }

function TGclControl.AddGclNode(ANode: TMeasureBillsIDTreeNode; AProjectIndex: Integer): TGclNode;
begin
  Result := FindGclNode(ANode.Rec);
  if not Assigned(Result) then
    Result := NewGclNode(ANode.Rec);
  with ANode.Rec do
  begin
    Result.Quantity := Result.Quantity + Quantity.AsFloat;
    Result.TotalPrice := Result.TotalPrice + TotalPrice.AsFloat;

    Result.P_Quantity[AProjectIndex] := Result.P_Quantity[AProjectIndex] + Quantity.AsFloat;
    Result.P_TotalPrice[AProjectIndex] := Result.P_TotalPrice[AProjectIndex] + TotalPrice.AsFloat;
  end;

  if Assigned(ANode.StageRec) then
    with ANode.StageRec do
    begin
      Result.CurGatherQuantity := Result.CurGatherQuantity + GatherQuantity.AsFloat;
      Result.CurGatherTotalPrice := Result.CurGatherTotalPrice + GatherTotalPrice.AsFloat;
      Result.P_CurGatherQuantity[AProjectIndex] := Result.P_CurGatherQuantity[AProjectIndex] + GatherQuantity.AsFloat;
      Result.P_CurGatherTotalPrice[AProjectIndex] := Result.P_CurGatherTotalPrice[AProjectIndex] + GatherTotalPrice.AsFloat;

      Result.EndGatherQuantity := Result.EndGatherQuantity + EndGatherQuantity.AsFloat;
      Result.EndGatherTotalPrice := Result.EndGatherTotalPrice + EndGatherTotalPrice.AsFloat;
      Result.P_EndGatherQuantity[AProjectIndex] := Result.P_EndGatherQuantity[AProjectIndex] + EndGatherQuantity.AsFloat;
      Result.P_EndGatherTotalPrice[AProjectIndex] := Result.P_EndGatherTotalPrice[AProjectIndex] + EndGatherTotalPrice.AsFloat;

      Result.PreGatherQuantity := Result.PreGatherQuantity + PreGatherQuantity.AsFloat;
      Result.PreGatherTotalPrice := Result.PreGatherTotalPrice + PreGatherTotalPrice.AsFloat;
    end;
end;

function TGclControl.B_CodeToChapter(const AB_Code: string): Integer;
var
  sgs: TStrings;
  iFirst, iSecond: Integer;
begin
  Result := 0;
  sgs := TStringList.Create;
  try
    sgs.Delimiter := '-';
    sgs.DelimitedText := AB_Code;
    iFirst := StrToIntDef(sgs.Strings[0], 0);
    Result := Trunc(iFirst/100);
    if (Result >= 90) and (Result < 100) then
      Result := 9;
  finally
    sgs.Free;
  end;
end;

procedure TGclControl.CalculateChapterGather;
var
  iIndex, iProject: Integer;
  vGclChapter: TGclChapter;
begin
  FGclChapterGather.TotalPrice := 0;
  FGclChapterGather.CurGatherTotalPrice := 0;
  FGclChapterGather.EndGatherTotalPrice := 0;
  FGclChapterGather.PreGatherTotalPrice := 0;
  for iProject := 0 to FProjectCount - 1 do
  begin
    FGclChapterGather.P_TotalPrice[iProject] := 0;
    FGclChapterGather.P_CurGatherTotalPrice[iProject] := 0;
    FGclChapterGather.P_EndGatherTotalPrice[iProject] := 0;
  end;

  for iIndex := 0 to FGclChapters.Count - 1 do
  begin
    vGclChapter := TGclChapter(FGclChapters.Items[iIndex]);
    with FGclChapterGather do
    begin
      TotalPrice := TotalPrice + vGclChapter.TotalPrice;
      CurGatherTotalPrice := CurGatherTotalPrice + vGclChapter.CurGatherTotalPrice;
      EndGatherTotalPrice := EndGatherTotalPrice + vGclChapter.EndGatherTotalPrice;
      PreGatherTotalPrice := PreGatherTotalPrice + vGclChapter.PreGatherTotalPrice;
      for iProject := 0 to FProjectCount - 1 do
      begin
        P_TotalPrice[iProject] := P_TotalPrice[iProject] + vGclChapter.P_TotalPrice[iProject];
        P_CurGatherTotalPrice[iProject] := P_CurGatherTotalPrice[iProject] + vGclChapter.P_CurGatherTotalPrice[iProject];
        P_EndGatherTotalPrice[iProject] := P_EndGatherTotalPrice[iProject] + vGclChapter.P_EndGatherTotalPrice[iProject];
      end;
    end;
  end;
end;

constructor TGclControl.Create(AProjectCount: Integer; AIsHaBai: Boolean);

  function CreateGclChapter(AChapterID: Integer; const AName: string): TGclChapter;
  begin
    Result := TGclChapter.Create(AChapterID, AName, FProjectCount);
    FGclChapters.Add(Result);
  end;

begin
  FProjectCount := AProjectCount;
  SetLength(FProjectName, AProjectCount);
  FGclNodes := TList.Create;
  FGclChapters := TList.Create;
  CreateGclChapter(1, '总 则');
  CreateGclChapter(2, '路 基');
  CreateGclChapter(3, '路 面');
  CreateGclChapter(4, '桥梁、涵洞工程');
  CreateGclChapter(5, '隧 道');
  CreateGclChapter(6, '安全设计及预埋管线');
  CreateGclChapter(7, '绿化及环境保护工程');
  if AIsHaBai then
  begin
    CreateGclChapter(8, '房建工程');
    CreateGclChapter(9, '机电工程');
  end
  else
  begin
    CreateGclChapter(8, '机电工程');
    CreateGclChapter(9, '房建工程');
  end;
  FOtherGcl := TGclChapter.Create(19, '非标准清单', FProjectCount);
  FGclChapterGather := TGclChapter.Create(20, '第100章至900章合计', FProjectCount);
end;

destructor TGclControl.Destroy;
begin
  FOtherGcl.Free;
  FGclChapterGather.Free;
  ClearObjects(FGclChapters);
  FGclChapters.Free;
  ClearObjects(FGclNodes);
  FGclNodes.Free;
end;

function TGclControl.FindGclNode(ARec: TBillsRecord): TGclNode;
var
  iIndex: Integer;
  vGclNode: TGclNode;
  bSameCode, bSameName, bSameUnits, bSamePrice: Boolean;
begin
  Result := nil;
  for iIndex := 0 to FGclNodes.Count - 1 do
  begin
    vGclNode := TGclNode(FGclNodes.Items[iIndex]);

    if (vGclNode.B_Code = ARec.B_Code.AsString) and
        (vGclNode.Name = ARec.Name.AsString) and
        (vGclNode.Units = ARec.Units.AsString) and
        (vGclNode.Price = ARec.Price.AsFloat) and
        (vGclNode.CalcType = ARec.CalcType.AsInteger)then
      begin
        Result := vGclNode;
        Break;
      end;
  end;
end;

function TGclControl.FindGclChapter(AChapterID: Integer): TGclChapter;
var
  iIndex: Integer;
  vChapter: TGclChapter;
begin
  Result := nil;
  for iIndex := 0 to FGclChapters.Count - 1 do
  begin
    vChapter := TGclChapter(FGclChapters.Items[iIndex]);
    if vChapter.ChapterID = AChapterID then
    begin
      Result := vChapter;
      Break;
    end;
  end;
end;

function TGclControl.GetGclChapter(AIndex: Integer): TGclChapter;
begin
  Result := TGclChapter(FGclChapters.Items[AIndex]);
end;

function TGclControl.GetGclChapterCount: Integer;
begin
  Result := FGclChapters.Count;
end;

procedure TGclControl.LinkGclChapter(AGclNode: TGclNode);
var
  iChapterID: Integer;
  vChapter: TGclChapter;
begin
  iChapterID := B_CodeToChapter(AGclNode.B_Code);
  vChapter := FindGclChapter(iChapterID);
  if Assigned(vChapter) then
    vChapter.AddGclNode(AGclNode)
  else
    FOtherGcl.AddGclNode(AGclNode);
end;

function TGclControl.NewGclNode(ARec: TBillsRecord): TGclNode;
begin
  Result := TGclNode.Create(FProjectCount);
  FGclNodes.Add(Result);
  Result.B_Code := ARec.B_Code.AsString;
  Result.Name := ARec.Name.AsString;
  Result.Units := ARec.Units.AsString;
  Result.Price := ARec.Price.AsFloat;
  Result.CalcType := ARec.CalcType.AsInteger;
  LinkGclChapter(Result);
end;

procedure TGclControl.Calculate;
var
  i: Integer;
begin
  for i := 0 to GclChapterCount - 1 do
    GclChapter[i].CalculateChapter;
  CalculateChapterGather;
end;

procedure TGclControl.ReCalculateTotalPrice;
var
  iGcl: Integer;
begin
  for iGcl := 0 to FGclNodes.Count - 1 do
    TGclNode(FGclNodes[iGcl]).Calculate;
end;

{ TGclChapter }

procedure TGclChapter.AddGclNode(AGclNode: TGclNode);
begin
  FGclNodes.Add(AGclNode);
end;

procedure TGclChapter.CalculateChapter;
var
  iIndex, iProject: Integer;
  vGclNode: TGclNode;
begin
  FTotalPrice := 0;
  FCurGatherTotalPrice := 0;
  FEndGatherTotalPrice := 0;
  FPreGatherTotalPrice := 0;
  for iProject := 0 to FProjectCount - 1 do
  begin
    FP_TotalPrice[iProject] := 0;
    FP_CurGatherTotalPrice[iProject] := 0;
    FP_EndGatherTotalPrice[iProject] := 0;
  end;

  for iIndex := 0 to FGclNodes.Count - 1 do
  begin
    vGclNode := TGclNode(FGclNodes.Items[iIndex]);
    FTotalPrice := FTotalPrice + vGclNode.TotalPrice;
    FCurGatherTotalPrice := FCurGatherTotalPrice + vGclNode.FCurGatherTotalPrice;
    FEndGatherTotalPrice := FEndGatherTotalPrice + vGclNode.FEndGatherTotalPrice;
    FPreGatherTotalPrice := FPreGatherTotalPrice + vGclNode.FPreGatherTotalPrice;
    for iProject := 0 to FProjectCount - 1 do
    begin
      FP_TotalPrice[iProject] := FP_TotalPrice[iProject] + vGclNode.P_TotalPrice[iProject];
      FP_CurGatherTotalPrice[iProject] := FP_CurGatherTotalPrice[iProject] + vGclNode.P_CurGatherTotalPrice[iProject];
      FP_EndGatherTotalPrice[iProject] := FP_EndGatherTotalPrice[iProject] + vGclNode.P_EndGatherTotalPrice[iProject];
    end;
  end;
end;

constructor TGclChapter.Create(AChapterID: Integer; const AName: string;
  AProjectCount: Integer);
begin
  FGclNodes := TList.Create;
  FChapterID := AChapterID;
  if FChapterID < 19 then
  begin
    FChapterBegin := FChapterID * 100;
    FChapterEnd := FChapterBegin + 99;
    FChapterName := Format('第%d章', [FChapterBegin]);
  end;
  FName := AName;
  FProjectCount := AProjectCount;
  SetLength(FP_TotalPrice, FProjectCount);
  SetLength(FP_CurGatherTotalPrice, FProjectCount);
  SetLength(FP_EndGatherTotalPrice, FProjectCount);
end;

destructor TGclChapter.Destroy;
begin
  FGclNodes.Free;
  inherited;
end;

function TGclChapter.GetCurPercent: Double;
begin
  if TotalPrice <> 0 then
    Result := CurGatherTotalPrice/TotalPrice*100
  else
    Result := 0;
end;

function TGclChapter.GetEndPercent: Double;
begin
  if TotalPrice <> 0 then
    Result := EndGatherTotalPrice/TotalPrice*100
  else
    Result := 0;
end;

function TGclChapter.GetGclNode(AIndex: Integer): TGclNode;
begin
  Result := TGclNode(FGclNodes.Items[AIndex]);
end;

function TGclChapter.GetGclNodeCount: Integer;
begin
  Result := FGclNodes.Count;
end;

{ TDealPayControl }

function TDealPayControl.AddMinusPayNode(const AName: string): TPayNode;
begin
  Result := FindMinusPayNode(AName);
  if not Assigned(Result) then
    Result := NewMinusPayNode(AName);
end;

function TDealPayControl.AddPayNode(const AName: string;
  AIsMinus: Boolean): TPayNode;
begin
  if AIsMinus then
    Result := AddMinusPayNode(AName)
  else
    Result := AddPlusPayNode(AName);
end;

function TDealPayControl.AddPlusPayNode(const AName: string): TPayNode;
begin
  Result := FindPlusPayNode(AName);
  if not Assigned(Result) then
    Result := NewPlusPayNode(AName);
end;

procedure TDealPayControl.CalculateAll;
begin
  CalculateGather(FPlusGather, FPlusPayNodes);
  CalculateGather(FMinusGather, FMinusPayNodes);
end;

procedure TDealPayControl.CalculateGather(AGather: TPayNode; ANodes: TList);
var
  i: Integer;
  vPayNode: TPayNode;
begin
  AGather.CurTotalPrice := 0;
  AGather.EndTotalPrice := 0;
  AGather.PreTotalPrice := 0;
  for i := 0 to ANodes.Count - 1 do
  begin
    vPayNode := TPayNode(ANodes.Items[i]);
    AGather.CurTotalPrice := AGather.CurTotalPrice + vPayNode.CurTotalPrice;
    AGather.EndTotalPrice := AGather.EndTotalPrice + vPayNode.EndTotalPrice;
    AGather.PreTotalPrice := AGather.PreTotalPrice + vPayNode.PreTotalPrice;
  end;
end;

constructor TDealPayControl.Create;
begin
  FPlusPayNodes := TList.Create;
  FMinusPayNodes := TList.Create;
  FPlusGather := TPayNode.Create;
  FMinusGather := TPayNode.Create;
  FGatherPayNode := TPayNode.Create;
  FGatherPayNode.Name := '本期应付';
  FCompletePayNode :=TPayNode.Create;
  FCompletePayNode.Name := '本期完成计量';
end;

destructor TDealPayControl.Destroy;
begin
  FCompletePayNode.Free;
  FGatherPayNode.Free;
  FMinusGather.Free;
  FPlusGather.Free;
  ClearObjects(FMinusPayNodes);
  FMinusPayNodes.Free;
  ClearObjects(FPlusPayNodes);
  FPlusPayNodes.Free;
  inherited;
end;

function TDealPayControl.FindMinusPayNode(const AName: string): TPayNode;
var
  iIndex: Integer;
  vPayNode: TPayNode;
begin
  Result := nil;
  for iIndex := 0 to FMinusPayNodes.Count -1 do
  begin
    vPayNode := TPayNode(FMinusPayNodes.Items[iIndex]);
    if (vPayNode.Name = AName) then
    begin
      Result := vPayNode;
      Break;
    end;
  end;
end;

function TDealPayControl.FindPlusPayNode(const AName: string): TPayNode;
var
  iIndex: Integer;
  vPayNode: TPayNode;
begin
  Result := nil;
  for iIndex := 0 to FPlusPayNodes.Count -1 do
  begin
    vPayNode := TPayNode(FPlusPayNodes.Items[iIndex]);
    if (vPayNode.Name = AName) then
    begin
      Result := vPayNode;
      Break;
    end;
  end;
end;

function TDealPayControl.GetMinusPayCount: Integer;
begin
  Result := FMinusPayNodes.Count;
end;

function TDealPayControl.GetMinusPayNode(AIndex: Integer): TPayNode;
begin
  Result := TPayNode(FMinusPayNodes.Items[AIndex]);
end;

function TDealPayControl.GetPlusPayCount: Integer;
begin
  Result := FPlusPayNodes.Count;
end;

function TDealPayControl.GetPlusPayNode(AIndex: Integer): TPayNode;
begin
  Result := TPayNode(FPlusPayNodes.Items[AIndex]);
end;

function TDealPayControl.NewMinusPayNode(const AName: string): TPayNode;
begin
  Result := TPayNode.Create;
  FMinusPayNodes.Add(Result);
  Result.Name := AName;
  Result.IsMinus := True;
end;

function TDealPayControl.NewPlusPayNode(const AName: string): TPayNode;
begin
  Result := TPayNode.Create;
  FPlusPayNodes.Add(Result);
  Result.Name := AName;
  Result.IsMinus := False;
end;

end.
