浏览代码

Merge branch 'sumUp'

Conflicts:
	Forms/MainFrm.dfm
	Forms/MainFrm.pas
	Frames/BillsCompileFme.dfm
	Units/ProjectData.pas
MaiXinRong 7 年之前
父节点
当前提交
ecb9103edc

+ 3 - 3
DataModules/StageDm.pas

@@ -25,9 +25,6 @@ type
     FBeforeChangeQuantity: Double;
     FBeforeChangeQuantity: Double;
     FBeforeChangeTotalPrice: Double;
     FBeforeChangeTotalPrice: Double;
 
 
-    procedure BeforeBatchOperation;
-    procedure AfterBatchOperation;
-
     procedure UpdateParentRecord(ABillsID: Integer; ATotalPrice: Double; const AFieldName: string);
     procedure UpdateParentRecord(ABillsID: Integer; ATotalPrice: Double; const AFieldName: string);
     procedure UpdateComplete(ABillsID: Integer; AQuantity, ATotalPrice: Double);
     procedure UpdateComplete(ABillsID: Integer; AQuantity, ATotalPrice: Double);
 
 
@@ -78,6 +75,9 @@ type
     procedure Open(AConnection: TADOConnection);
     procedure Open(AConnection: TADOConnection);
     procedure Save;
     procedure Save;
 
 
+    procedure BeforeBatchOperation;
+    procedure AfterBatchOperation;
+
     // 计算任一清单节点的价差金额,并增量汇总至父项
     // 计算任一清单节点的价差金额,并增量汇总至父项
     procedure CalculatePriceMargin(ABillsID: Integer);
     procedure CalculatePriceMargin(ABillsID: Integer);
     // 计算材料调差节点
     // 计算材料调差节点

+ 7 - 4
DataModules/ZJJLDm.pas

@@ -530,9 +530,12 @@ procedure TZJJLData.CheckZjjlVerison;
     for i := 0 to sddZJJL.RecordCount - 1 do
     for i := 0 to sddZJJL.RecordCount - 1 do
     begin
     begin
       Rec := sddZJJL.Records[i];
       Rec := sddZJJL.Records[i];
-      SetHistory('CertificateCode', Rec.ValueByName('CertificateCode').AsString, Rec);
-      SetHistory('FormulaMemo', Rec.ValueByName('FormulaMemo').AsString, Rec);
-      SetHistory('RelaFile', Rec.ValueByName('RelaFile').AsString, Rec);
+      if Rec.ValueByName('CertificateCode').AsString <> '' then
+        SetHistory('CertificateCode', Rec.ValueByName('CertificateCode').AsString, Rec);
+      if Rec.ValueByName('FormulaMemo').AsString <> '' then
+        SetHistory('FormulaMemo', Rec.ValueByName('FormulaMemo').AsString, Rec);
+      if Rec.ValueByName('RelaFile').AsString <> '' then
+        SetHistory('RelaFile', Rec.ValueByName('RelaFile').AsString, Rec);
     end;
     end;
   end;
   end;
 
 
@@ -735,7 +738,7 @@ procedure TZJJLData.sdvZJJLBeforeValueChange(AValue: TsdValue;
 var
 var
   sNewValue: string;
   sNewValue: string;
 begin
 begin
-  if CheckFieldNeedHistory(AValue.FieldName) then
+  if CheckFieldNeedHistory(AValue.FieldName) and not TPhaseData(FPhaseData).StageDataReadOnly then
   begin
   begin
     sNewValue := VarToStrDef(NewValue, '');
     sNewValue := VarToStrDef(NewValue, '');
     if sNewValue <> AValue.AsString then
     if sNewValue <> AValue.AsString then

+ 72 - 0
Forms/MainFrm.dfm

@@ -390,6 +390,7 @@ object MainForm: TMainForm
           Visible = True
           Visible = True
         end
         end
         item
         item
+          BeginGroup = True
           Item = dxsiImportExcel
           Item = dxsiImportExcel
           Visible = True
           Visible = True
         end
         end
@@ -398,6 +399,7 @@ object MainForm: TMainForm
           Visible = True
           Visible = True
         end
         end
         item
         item
+          BeginGroup = True
           Item = dxbtnExportCloudTenderFile
           Item = dxbtnExportCloudTenderFile
           Visible = True
           Visible = True
         end
         end
@@ -406,8 +408,18 @@ object MainForm: TMainForm
           Visible = True
           Visible = True
         end
         end
         item
         item
+          BeginGroup = True
           Item = dxbtnImportDmf
           Item = dxbtnImportDmf
           Visible = True
           Visible = True
+        end
+        item
+          BeginGroup = True
+          Item = dxbtnExportSumBaseFile
+          Visible = True
+        end
+        item
+          Item = dxbtnImportSubTenderGather
+          Visible = True
         end>
         end>
     end
     end
     object dxsiEdit: TdxBarSubItem
     object dxsiEdit: TdxBarSubItem
@@ -1000,6 +1012,10 @@ object MainForm: TMainForm
         item
         item
           Item = dxbtnTenderPartition
           Item = dxbtnTenderPartition
           Visible = True
           Visible = True
+        end
+        item
+          Item = dxbtnGatherSubTender
+          Visible = True
         end>
         end>
     end
     end
     object dxbtnTenderPartition: TdxBarButton
     object dxbtnTenderPartition: TdxBarButton
@@ -1124,12 +1140,56 @@ object MainForm: TMainForm
       Hint = #23450#20301#33267#21488#36134#20998#35299
       Hint = #23450#20301#33267#21488#36134#20998#35299
       Visible = ivAlways
       Visible = ivAlways
     end
     end
+<<<<<<< HEAD
     object dxbtnGclGatherZJJL: TdxBarButton
     object dxbtnGclGatherZJJL: TdxBarButton
       Caption = #35745#37327#27719#24635#26684#24335
       Caption = #35745#37327#27719#24635#26684#24335
       Category = 0
       Category = 0
       Hint = #35745#37327#27719#24635#26684#24335
       Hint = #35745#37327#27719#24635#26684#24335
       Visible = ivAlways
       Visible = ivAlways
     end
     end
+=======
+    object dxbtnExportSumBaseFile: TdxBarButton
+      Action = actnExportSumBaseFile
+      Category = 0
+      Hint = #23548#20986#24635#21253#22522#20934#25991#20214
+    end
+    object dxbtnGatherSubTender: TdxBarButton
+      Caption = #20998#21253#26631#27573#27719#24635
+      Category = 0
+      Hint = #20998#21253#26631#27573#27719#24635
+      Visible = ivAlways
+      OnClick = dxbtnGatherSubTenderClick
+    end
+    object dxbtnExportTenderError: TdxBarButton
+      Caption = #23548#20986#21333#26631#27573#38169#35823#20449#24687
+      Category = 0
+      Hint = #23548#20986#21333#26631#27573#38169#35823#20449#24687
+      Visible = ivAlways
+    end
+    object dxbtnExportAllError: TdxBarButton
+      Caption = #23548#20986#20840#37096#38169#35823#20449#24687
+      Category = 0
+      Hint = #23548#20986#20840#37096#38169#35823#20449#24687
+      Visible = ivAlways
+    end
+    object dxbtnExportStgResultExcel: TdxBarButton
+      Caption = #23548#20986#20998#21253#27719#24635#32467#26524
+      Category = 0
+      Hint = #23548#20986#20998#21253#27719#24635#32467#26524
+      Visible = ivAlways
+      ImageIndex = 13
+    end
+    object dxbtnExportStgResult: TdxBarButton
+      Caption = #23548#20986#20998#21253#27719#24635#32467#26524
+      Category = 0
+      Hint = #23548#20986#20998#21253#27719#24635#32467#26524
+      Visible = ivAlways
+    end
+    object dxbtnImportSubTenderGather: TdxBarButton
+      Action = actnImportSubTenderGather
+      Category = 0
+    end
+>>>>>>> sumUp
   end
   end
   object Images: TImageList
   object Images: TImageList
     DrawingStyle = dsTransparent
     DrawingStyle = dsTransparent
@@ -3303,6 +3363,18 @@ object MainForm: TMainForm
       OnExecute = actnImportDmfExecute
       OnExecute = actnImportDmfExecute
       OnUpdate = actnImportCloudTenderFileUpdate
       OnUpdate = actnImportCloudTenderFileUpdate
     end
     end
+    object actnExportSumBaseFile: TAction
+      Category = 'File'
+      Caption = #23548#20986#24635#21253#22522#20934#25991#20214
+      OnExecute = actnExportSumBaseFileExecute
+      OnUpdate = actnUnlockInfoUpdate
+    end
+    object actnImportSubTenderGather: TAction
+      Category = 'File'
+      Caption = #23548#20837#20998#21253#27719#24635#25968#25454
+      OnExecute = actnImportSubTenderGatherExecute
+      OnUpdate = actnImportSubTenderGatherUpdate
+    end
   end
   end
   object dxpmTabSet: TdxBarPopupMenu
   object dxpmTabSet: TdxBarPopupMenu
     BarManager = dxBarManager
     BarManager = dxBarManager

+ 80 - 1
Forms/MainFrm.pas

@@ -168,7 +168,19 @@ type
     dxbtnLocateZJJL: TdxBarButton;
     dxbtnLocateZJJL: TdxBarButton;
     dxbtnEpure: TdxBarButton;
     dxbtnEpure: TdxBarButton;
     dxbtnLocateCompileBills: TdxBarButton;
     dxbtnLocateCompileBills: TdxBarButton;
+<<<<<<< HEAD
     dxbtnGclGatherZJJL: TdxBarButton;
     dxbtnGclGatherZJJL: TdxBarButton;
+=======
+    dxbtnExportSumBaseFile: TdxBarButton;
+    actnExportSumBaseFile: TAction;
+    dxbtnGatherSubTender: TdxBarButton;
+    dxbtnExportTenderError: TdxBarButton;
+    dxbtnExportAllError: TdxBarButton;
+    dxbtnExportStgResultExcel: TdxBarButton;
+    dxbtnExportStgResult: TdxBarButton;
+    dxbtnImportSubTenderGather: TdxBarButton;
+    actnImportSubTenderGather: TAction;
+>>>>>>> sumUp
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure jtsProjectsChange(Sender: TObject; NewTab: Integer;
     procedure jtsProjectsChange(Sender: TObject; NewTab: Integer;
@@ -214,6 +226,10 @@ type
     procedure dxbtnTenderPartitionClick(Sender: TObject);
     procedure dxbtnTenderPartitionClick(Sender: TObject);
     procedure actnImportDmfExecute(Sender: TObject);
     procedure actnImportDmfExecute(Sender: TObject);
     procedure dxbtnHelpCenterClick(Sender: TObject);
     procedure dxbtnHelpCenterClick(Sender: TObject);
+    procedure actnExportSumBaseFileExecute(Sender: TObject);
+    procedure dxbtnGatherSubTenderClick(Sender: TObject);
+    procedure actnImportSubTenderGatherExecute(Sender: TObject);
+    procedure actnImportSubTenderGatherUpdate(Sender: TObject);
   private
   private
     FProjectManagerFrame: TProjectManagerFrame;
     FProjectManagerFrame: TProjectManagerFrame;
     FProjectFrames: TList;
     FProjectFrames: TList;
@@ -251,7 +267,8 @@ uses
   ProjectProperty, ConstUnit, PHPWebDm, Math, ShellAPI,
   ProjectProperty, ConstUnit, PHPWebDm, Math, ShellAPI,
   FindUserFrm, ImportExcelHintFrm, ConfigDoc, ExportExcel,
   FindUserFrm, ImportExcelHintFrm, ConfigDoc, ExportExcel,
   ProjectCommands, BillsCompileDm, tpMainFrm,
   ProjectCommands, BillsCompileDm, tpMainFrm,
-  DealBillsExcelImport, ExcelImport_Bills, DetailExcelImport;
+  DealBillsExcelImport, ExcelImport_Bills, DetailExcelImport,
+  stgGatherControl, stgSelectFileFrm;
 
 
 {$R *.dfm}
 {$R *.dfm}
 {$R MeasureIcons.RES}
 {$R MeasureIcons.RES}
@@ -875,4 +892,66 @@ begin
   MeasureLog.AppendLogTo(AE.Message);
   MeasureLog.AppendLogTo(AE.Message);
 end;
 end;
 
 
+procedure TMainForm.actnExportSumBaseFileExecute(Sender: TObject);
+var
+  sFileName: string;
+  Exportor: TTenderExport;
+  Rec: TsdDataRecord;
+begin
+  // 导出前先保存
+  CurProjectFrame.ProjectData.SaveAndCheck;
+  // 导出云版专用
+  sFileName := SupportManager.ConfigInfo.OutputPath + CurProjectFrame.ProjectData.ProjectName + '.sbf';
+  if SaveFile(sFileName, '.sbf') then
+  begin
+    if FileExists(sFileName) and not QuestMessage(Format('存在同名文件“%s”,是否替换?', [ExtractFileName(sFileName)])) then
+      Exit;
+
+    Screen.Cursor := crHourGlass;
+    try
+      Rec := ProjectManagerFrame.Rec(CurProjectFrame.ProjectData.ProjectID);
+      Exportor := TTenderExport.Create(Rec, sFileName);
+      try
+        Exportor.Execute;
+      finally
+        Exportor.Free;
+      end;
+    finally
+      Screen.Cursor := crDefault;
+    end;
+  end;
+end;
+
+procedure TMainForm.dxbtnGatherSubTenderClick(Sender: TObject);
+var
+  gc: TstgGatherControl;
+begin
+  gc := TstgGatherControl.Create;
+  Screen.Cursor := crHourGlass;
+  try
+    if SelectFileForSubTenderGather(gc) then
+      gc.Gather;
+  finally
+    gc.Free;
+    Screen.Cursor := crDefault;
+  end;
+end;
+
+procedure TMainForm.actnImportSubTenderGatherExecute(Sender: TObject);
+var
+  sFileName: string;
+begin
+  if CurProjectFrame.ProjectData.ProjProperties.PhaseCount = 0 then
+    WarningMessage('未开始计量,请在开始计量后再导入分包汇总数据。')
+  else if CurProjectFrame.ProjectData.StageDataReadOnly then
+    WarningMessage('当前正在查看往期数据,请切换至最新一起再导入分包汇总数据。')
+  else if SelectFile(sFileName, '.sgf') then
+    CurProjectFrame.ProjectData.ImportSubTenderGather(sFileName);
+end;
+
+procedure TMainForm.actnImportSubTenderGatherUpdate(Sender: TObject);
+begin
+  TAction(Sender).Enabled := (jtsProjects.Tabs.Count > 1) and Assigned(CurProjectFrame);
+end;
+
 end.
 end.

+ 14 - 13
Frames/BillsCompileFme.dfm

@@ -53,7 +53,11 @@ object BillsCompileFrame: TBillsCompileFrame
       Height = 376
       Height = 376
       Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection, goShowTreeLine]
       Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection, goShowTreeLine]
       OptionsEx = []
       OptionsEx = []
+<<<<<<< HEAD
       ColCount = 25
       ColCount = 25
+=======
+      ColCount = 26
+>>>>>>> sumUp
       RowCount = 7
       RowCount = 7
       FixedRowCount = 3
       FixedRowCount = 3
       ShowGridLine = False
       ShowGridLine = False
@@ -678,7 +682,7 @@ object BillsCompileFrame: TBillsCompileFrame
         ReadOnly = False
         ReadOnly = False
       end
       end
       item
       item
-        Title.Caption = 'ID'
+        Title.Caption = 'ChapterParentID'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossRows = 3
         Title.CaptionAcrossRows = 3
         Title.Font.Charset = GB2312_CHARSET
         Title.Font.Charset = GB2312_CHARSET
@@ -692,13 +696,13 @@ object BillsCompileFrame: TBillsCompileFrame
         Font.Height = -12
         Font.Height = -12
         Font.Name = #23435#20307
         Font.Name = #23435#20307
         Font.Style = []
         Font.Style = []
-        FieldName = 'ID'
+        FieldName = 'ChapterParentID'
         Width = 50
         Width = 50
         Visible = False
         Visible = False
-        ReadOnly = True
+        ReadOnly = False
       end
       end
       item
       item
-        Title.Caption = 'ParentID'
+        Title.Caption = 'ID'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossRows = 3
         Title.CaptionAcrossRows = 3
         Title.Font.Charset = GB2312_CHARSET
         Title.Font.Charset = GB2312_CHARSET
@@ -712,13 +716,12 @@ object BillsCompileFrame: TBillsCompileFrame
         Font.Height = -12
         Font.Height = -12
         Font.Name = #23435#20307
         Font.Name = #23435#20307
         Font.Style = []
         Font.Style = []
-        FieldName = 'ParentID'
+        FieldName = 'ID'
         Width = 50
         Width = 50
-        Visible = False
         ReadOnly = True
         ReadOnly = True
       end
       end
       item
       item
-        Title.Caption = 'NextSiblingID'
+        Title.Caption = 'ParentID'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossRows = 3
         Title.CaptionAcrossRows = 3
         Title.Font.Charset = GB2312_CHARSET
         Title.Font.Charset = GB2312_CHARSET
@@ -732,13 +735,12 @@ object BillsCompileFrame: TBillsCompileFrame
         Font.Height = -12
         Font.Height = -12
         Font.Name = #23435#20307
         Font.Name = #23435#20307
         Font.Style = []
         Font.Style = []
-        FieldName = 'NextSiblingID'
+        FieldName = 'ParentID'
         Width = 50
         Width = 50
-        Visible = False
         ReadOnly = True
         ReadOnly = True
       end
       end
       item
       item
-        Title.Caption = 'ChapterParentID'
+        Title.Caption = 'NextSiblingID'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossRows = 3
         Title.CaptionAcrossRows = 3
         Title.Font.Charset = GB2312_CHARSET
         Title.Font.Charset = GB2312_CHARSET
@@ -752,10 +754,9 @@ object BillsCompileFrame: TBillsCompileFrame
         Font.Height = -12
         Font.Height = -12
         Font.Name = #23435#20307
         Font.Name = #23435#20307
         Font.Style = []
         Font.Style = []
-        FieldName = 'ChapterParentID'
+        FieldName = 'NextSiblingID'
         Width = 50
         Width = 50
-        Visible = False
-        ReadOnly = False
+        ReadOnly = True
       end>
       end>
     Grid = zgBillsCompile
     Grid = zgBillsCompile
     ExtendRowCount = 3
     ExtendRowCount = 3

+ 276 - 0
SubTenderGather/stgExcelExport.pas

@@ -0,0 +1,276 @@
+unit stgExcelExport;
+
+interface
+
+uses
+  Classes, OExport, OExport_Vcl, OExport_VclForms, stgGatherDm, sdDB,
+  stgGatherCacheData, stgGatherUtils, sdIDTree, Graphics;
+
+type
+  TstgExcelExport = class
+  private
+    FTempFile: string;
+    FGatherData: TstgGatherData;
+    FOExport: TOExport;
+    FOExportor: TOCustomExporter;
+  protected
+    function AddHeadCell(ARow: TExportRow; const AHead: string; AWidth: Integer): TExportCellString;
+
+    function GetExportor(const AFileType: string): TOCustomExporter;
+
+    procedure SaveFile(const AFileName: string);
+
+    procedure BeforeExport;
+    procedure AfterExport;
+  public
+    constructor Create(AGatherData: TstgGatherData);
+
+    property GatherData: TstgGatherData read FGatherData;
+    property OExport: TOExport read FOExport;
+  end;
+
+  TstgErrorExcelExport = class(TstgExcelExport)
+  private
+    procedure InitSheet(ASheet: TExportWorkSheet);
+    procedure ExportSubTenderToSheet(ATenderID: Integer; ASheet: TExportWorkSheet);
+  public
+    procedure ExportSubTender(ARec: TsdDataRecord; const AFileName: string);
+    procedure ExportAll(const AFileName: string);
+  end;
+
+  TstgGatherExcelExport = class(TstgExcelExport)
+  private
+    procedure InitSheet(ASheet: TExportWorkSheet);
+    procedure ExportTreeNodeToSheet(ANode: TsdIDTreeNode; ASheet: TExportWorkSheet);
+    procedure ExportGatherToSheet(ASheet: TExportWorkSheet);
+  public
+    procedure ExportGather(const AFileName: string);
+  end;
+
+implementation
+
+uses SysUtils, UtilMethods, ZhAPI;
+
+{ TstgErrorExcelExport }
+
+procedure TstgErrorExcelExport.ExportAll(const AFileName: string);
+var
+  i: Integer;
+  vRec: TsdDataRecord;
+begin
+  BeforeExport;
+  try
+    GetExportor(ExtractFileExt(AFileName));
+    for i := 0 to FGatherData.sddSubTenders.RecordCount - 1 do
+    begin
+      vRec := FGatherData.sddSubTenders.Records[i];
+      ExportSubTenderToSheet(vRec.ValueByName('ID').AsInteger, FOExport.AddWorkSheet(vRec.ValueByName('Name').AsString));
+    end;
+    SaveFile(AFileName);
+  finally
+    AfterExport;
+  end;
+end;
+
+procedure TstgErrorExcelExport.ExportSubTender(ARec: TsdDataRecord;
+  const AFileName: string);
+begin
+  BeforeExport;
+  try
+    GetExportor(ExtractFileExt(AFileName));
+    ExportSubTenderToSheet(ARec.ValueByName('ID').AsInteger, FOExport.AddWorkSheet(ARec.ValueByName('Name').AsString));
+    SaveFile(AFileName);
+  finally
+    AfterExport;
+  end;
+end;
+
+procedure TstgErrorExcelExport.ExportSubTenderToSheet(ATenderID: Integer;
+  ASheet: TExportWorkSheet);
+
+  procedure ExportErrorRecord(ARec: TsdDataRecord);
+  var
+    vRow: TExportRow;
+    vCell: TExportCell;
+  begin
+    vRow := ASheet.AddRow;
+    vCell := vRow.AddCellString(ARec.ValueByName('RelaCode').AsString);
+    vCell := vRow.AddCellString(ARec.ValueByName('RelaSerialNo').AsString);
+    vCell.SetAlignment(cahCenter);
+    vCell := vRow.AddCellString(ARec.ValueByName('DetailCode').AsString);
+    vCell := vRow.AddCellString(ARec.ValueByName('DetailSerialNo').AsString);
+    vCell.SetAlignment(cahCenter);
+    vCell := vRow.AddCellString(GetErrorTypeText(ARec.ValueByName('ErrorType').AsInteger));
+  end;
+
+var
+  vIdx: TsdIndex;
+  i, iBegin, iEnd: Integer;
+  vRec: TsdDataRecord;
+begin
+  InitSheet(ASheet);
+  vIdx := GatherData.sddErrorDetail.FindIndex('idxTenderID');
+  iBegin := vIdx.FindKeyIndex(ATenderID);
+  iEnd := vIdx.FindKeyLastIndex(ATenderID);
+  if iBegin = -1 then Exit;
+  for i := iBegin to iEnd do
+    ExportErrorRecord(vIdx.Records[i]);
+end;
+
+procedure TstgErrorExcelExport.InitSheet(ASheet: TExportWorkSheet);
+var
+  vRow: TExportRow;
+  vCell: TExportCellString;
+begin
+  vRow := ASheet.AddRow;
+  vCell := AddHeadCell(vRow, '出错源', 120);
+  vCell.ColSpan := 2;
+  vCell := AddHeadCell(vRow, '可计量清单', 80);
+  vCell.ColSpan := 2;
+  vCell := AddHeadCell(vRow, '错误原因', 200);
+  vCell.RowSpan := 2;
+
+  vRow := ASheet.Rows.Items[vRow.RowIndex + 1];
+  vCell := AddHeadCell(vRow, '编号', 120);
+  vCell := AddHeadCell(vRow, '行号', 50);
+  vCell := AddHeadCell(vRow, '编号', 80);
+  vCell := AddHeadCell(vRow, '行号', 50);
+end;
+
+{ TstgExcelExport }
+
+function TstgExcelExport.AddHeadCell(ARow: TExportRow; const AHead: string;
+  AWidth: Integer): TExportCellString;
+begin
+  Result := ARow.AddCellString(AHead);
+  Result.SetAlignment(cahCenter);
+  Result.SetVAlignment(cavCenter);
+  Result.Font.Name := '黑体';
+  Result.Font.Size := 10;
+  Result.Width := AWidth;
+end;
+
+procedure TstgExcelExport.AfterExport;
+begin
+  FOExport.Free;
+  if Assigned(FOExportor) then
+    FOExportor.Free;
+  if FileExists(FTempFile) then
+    DeleteFile(FTempFile);
+end;
+
+procedure TstgExcelExport.BeforeExport;
+begin
+  FOExport := TOExport.Create;
+  FOExport.UseProgress := False;
+  FTempFile := GetTempFileName;
+end;
+
+constructor TstgExcelExport.Create(AGatherData: TstgGatherData);
+begin
+  FGatherData := AGatherData;
+end;
+
+function TstgExcelExport.GetExportor(
+  const AFileType: string): TOCustomExporter;
+begin
+  if SameText(AFileType, '.xls') then
+    FOExportor := TOCustomExporterXLS.Create
+  else //if SameText(AFileType, '.xlsx') then
+    FOExportor := TOCustomExporterXLSX.Create;
+end;
+
+procedure TstgExcelExport.SaveFile(const AFileName: string);
+begin
+  FOExport.SaveToFile(FTempFile, FOExportor);
+  if not FileExists(AFileName) or QuestMessage('存在同名文件,是否替换?') then
+    CopyFileOrFolder(FTempFile, AFileName);
+end;
+
+{ TstgGatherExcelExport }
+
+procedure TstgGatherExcelExport.ExportGather(const AFileName: string);
+begin
+  BeforeExport;
+  try
+    GetExportor(ExtractFileExt(AFileName));
+    ExportGatherToSheet(OExport.AddWorkSheet('分包数据汇总'));
+    SaveFile(AFileName);
+  finally
+    AfterExport;
+  end;
+end;
+
+procedure TstgGatherExcelExport.ExportGatherToSheet(
+  ASheet: TExportWorkSheet);
+var
+  vTree: TsdIDTree;
+begin
+  InitSheet(ASheet);
+  vTree := TsdIDTree.Create;
+  try
+    vTree.KeyFieldName := 'ID';
+    vTree.ParentFieldName := 'ParentID';
+    vTree.NextSiblingFieldName := 'NextSiblingID';
+    vTree.DataView := GatherData.sdvGatherTree;
+    ExportTreeNodeToSheet(vTree.FirstNode, ASheet);
+  finally
+    vTree.Free;
+  end;
+end;
+
+procedure TstgGatherExcelExport.ExportTreeNodeToSheet(ANode: TsdIDTreeNode;
+  ASheet: TExportWorkSheet);
+
+  procedure AddCellString(ARow: TExportRow; const AStr: string; AColor: TColor);
+  var
+    vCell: TExportCellString;
+  begin
+    vCell := ARow.AddCellString(AStr);
+    vCell.Font.Color := AColor;
+  end;
+
+  procedure AddCellNumber(ARow: TExportRow; const ANum: Double; AColor: TColor);
+  var
+    vCell: TExportCellNumber;
+  begin
+    vCell := ARow.AddCellNumber(ANum);
+    vCell.Font.Color := AColor;
+    vCell.EmptyIfZero := True;
+  end;
+
+var
+  vColor: TColor;
+  vRow: TExportRow;
+  vCell: TExportCellNumber;
+begin
+  if not Assigned(ANode) then Exit;
+  if ANode.Rec.ValueByName('IsSubTender').AsBoolean then
+    vColor := $00D5D5D5
+  else
+    vColor := clWindowText;
+  vRow := ASheet.AddRow;
+  AddCellString(vRow, ANode.Rec.ValueByName('Code').AsString, vColor);
+  AddCellString(vRow, ANode.Rec.ValueByName('B_Code').AsString, vColor);
+  AddCellString(vRow, ANode.Rec.ValueByName('Name').AsString, vColor);
+  AddCellString(vRow, ANode.Rec.ValueByName('Units').AsString, vColor);
+  AddCellNumber(vRow, ANode.Rec.ValueByName('DealQuantity').AsFloat, vColor);
+  AddCellNumber(vRow, ANode.Rec.ValueByName('QcQuantity').AsFloat, vColor);
+  ExportTreeNodeToSheet(ANode.FirstChild, ASheet);
+  ExportTreeNodeToSheet(ANode.NextSibling, ASheet);
+end;
+
+procedure TstgGatherExcelExport.InitSheet(ASheet: TExportWorkSheet);
+var
+  vRow: TExportRow;
+begin
+  vRow := ASheet.AddRow;
+  AddHeadCell(vRow, '项目节编号', 180);
+  AddHeadCell(vRow, '清单编号', 80);
+  AddHeadCell(vRow, '名称', 240);
+  AddHeadCell(vRow, '单位', 50);
+  AddHeadCell(vRow, '合同计量', 100);
+  AddHeadCell(vRow, '数量变更计量', 100);
+end;
+
+end.

+ 429 - 0
SubTenderGather/stgGather.pas

@@ -0,0 +1,429 @@
+unit stgGather;
+
+interface
+
+uses
+  Classes, stgGatherCacheData, ProjectData, BillsTree, sdIDTree;
+
+type
+  TProgramHintEvent = procedure (const ATenderName: string) of Object;
+
+  TstgSumBaseFileLoader = class
+  private
+    FTree: TstgGatherTree;
+    FSumBaseFile: string;
+    FTempFolder: string;
+    FFileName: string;
+    FProjectData: TProjectData;
+
+    procedure LoadFileName;
+    function LoadTreeNodeData(ANode: TBillsIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
+    procedure LoadSumBaseTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
+  public
+    constructor Create(ATree: TstgGatherTree; const ASumBaseFile: string);
+    destructor Destroy; override;
+
+    procedure LoadData;
+  end;
+
+  TstgSubTenderFileGather = class
+  private
+    FCacheData: TstgGatherCacheData;
+    FProjectData: TProjectData;
+    FCurSubTenderID: Integer;
+    FLoadHint: TProgramHintEvent;
+    procedure GatherDetailData(AGatherNode: TstgGatherTreeNode; ASourceNode: TMeasureBillsIDTreeNode);
+    function GatherSubTenderTreeNodeData(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
+    procedure GatherSubTenderTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
+    procedure GatherSubTender(ASubTenderID: Integer);
+  public
+    procedure GatherTo(AGatherCacheData: TstgGatherCacheData; ASubTenders: TList);
+
+    property LoadHint: TProgramHintEvent read FLoadHint write FLoadHint;
+  end;
+
+  TstgErrorChecker = class
+  private
+    FCacheData: TstgGatherCacheData;
+
+    procedure NewError(ANode: TstgGatherTreeNode; AType: Integer);
+
+    function SafeCheckParent(ANode, ACheckParent: TstgGatherTreeNode): TstgGatherTreeNode;
+
+    // ACheckParent的子项(总包中存在),存在与ANode同编号节点
+    function HasSameCodeLevelChild(ANode: TstgGatherTreeNode;
+      ACheckParent: tstgGatherTreeNode = nil): Boolean;
+    // ACheckParent的子项(总包中存在),存在与ANode同编号、名称、单位,但不同层次节点
+    function HasSameChildWithDiffLevel(ANode: TstgGatherTreeNode;
+      ACheckParent: TstgGatherTreeNode = nil): Boolean;
+    // ACheckParent的子项(总包中存在)(含子项的子项),存在与ANode同编号节点
+    // 子项(含子项的子项),存在与CheckParent的子项(总包中存在)同编号节点
+
+    function HasShortRelaCodeChild(ANode: TstgGatherTreeNode): Boolean;
+    function HasLongRelaCodeChild(ANode:TstgGatherTreeNode): Boolean;
+    function HasXmjChildWithSameCodeChild(ANode: TstgGatherTreeNode): Boolean;
+
+    procedure AddXmjError(ANode: TstgGatherTreeNode);
+    procedure AddGclError(ANode: TstgGatherTreeNode);
+
+    procedure AddError(ANode: TstgGatherTreeNode);
+  public
+    procedure Check(AGatherCacheData: TstgGatherCacheData);
+  end;
+
+implementation
+
+uses Math, Globals, mDataRecord, UtilMethods, SysUtils, XMLDoc, XMLIntf,
+  CacheTree;
+
+{ TstgSumBaseFileLoader }
+
+constructor TstgSumBaseFileLoader.Create(ATree: TstgGatherTree;
+  const ASumBaseFile: string);
+begin
+  FTree := ATree;
+  FSumBaseFile := ASumBaseFile;
+  FTempFolder := GenerateTempFolder(GetTempFilePath);
+  FProjectData := TProjectData.Create;
+end;
+
+destructor TstgSumBaseFileLoader.Destroy;
+begin
+  if FileExists(FTempFolder) then
+    DeleteFolder(FTempFolder);
+  if Assigned(FProjectData) then
+    FProjectData.Free;
+  inherited;
+end;
+
+procedure TstgSumBaseFileLoader.LoadData;
+begin
+  UnZipFile(FSumBaseFile, FTempFolder);
+  LoadFileName;
+  FProjectData.OpenForSumUpBase(FTempFolder + '\' + FFileName);
+  LoadSumBaseTreeNode(FProjectData.BillsCompileData.BillsCompileTree.FirstNode, nil);
+  FTree.MarkLeafXmj;
+end;
+
+procedure TstgSumBaseFileLoader.LoadFileName;
+var
+  FXmlDocument: IXMLDocument;
+  RootXmlNode, InfoXmlNode: IXMLNode;
+  ChildNodes: IXMLNodeList;
+begin
+  FXmlDocument := TXMLDocument.Create(nil) as IXMLDocument;
+  try
+    FXmlDocument.LoadFromFile(FTempFolder + '\Info.xml');
+    FXmlDocument.Options := [doNodeAutoCreate,doNodeAutoIndent,doAutoPrefix,doNamespaceDecl];
+    RootXmlNode := FXmlDocument.DocumentElement;
+
+    ChildNodes := RootXmlNode.ChildNodes;
+    InfoXmlNode := ChildNodes.FindNode('ProjectInfo');
+
+    FFileName := InfoXmlNode.Attributes['FileName'];
+  finally
+    FXmlDocument := nil;
+  end;
+end;
+
+procedure TstgSumBaseFileLoader.LoadSumBaseTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
+var
+  vCurGatherNode: TstgGatherTreeNode;
+begin
+  if not Assigned(ANode) then Exit;
+  vCurGatherNode := LoadTreeNodeData(TBillsIDTreeNode(ANode), AParent);
+  LoadSumBaseTreeNode(ANode.FirstChild, vCurGatherNode);
+  LoadSumBaseTreeNode(ANode.NextSibling, AParent);
+end;
+
+function TstgSumBaseFileLoader.LoadTreeNodeData(ANode: TBillsIDTreeNode;
+  AParent: TstgGatherTreeNode): TstgGatherTreeNode;
+begin
+  Result := FTree.AddSumBaseNode(AParent, ANode.ID);
+  Result.Code := ANode.Rec.Code.AsString;
+  Result.B_Code := ANode.Rec.B_Code.AsString;
+  Result.Name := ANode.Rec.Name.AsString;
+  Result.Units := ANode.Rec.Units.AsString;
+  Result.IsLeaf := not ANode.HasChildren;
+end;
+
+{ TstgSubTenderFileGather }
+
+procedure TstgSubTenderFileGather.GatherDetailData(
+  AGatherNode: TstgGatherTreeNode; ASourceNode: TMeasureBillsIDTreeNode);
+var
+  vSubTender: TstgSubTenderStageData;
+begin
+  //if Assigned(ASourceNode.StageRec) and
+  //   ((ASourceNode.StageRec.GatherQuantity.AsFloat <> 0) or (ASourceNode.StageRec.GatherTotalPrice.AsFloat <> 0)) then
+  
+  //if not ASourceNode.HasChildren then
+  if (AGatherNode.IsSubTender) or (not ASourceNode.HasChildren) then
+  begin
+    vSubTender := AGatherNode.SafeSubTender(FCurSubTenderID);
+    vSubTender.AddDetail(ASourceNode);
+  end;
+end;
+
+procedure TstgSubTenderFileGather.GatherSubTender(ASubTenderID: Integer);
+var
+  vNode: TsdIDTreeNode;
+begin
+  FCurSubTenderID := ASubTenderID;
+  vNode := ProjectManager.ProjectsTree.FindNode(ASubTenderID);
+  if vNode.Rec.ValueByName('Type').AsInteger = 1 then
+  begin;
+    FLoadHint(vNode.Rec.ValueByName('Name').AsString);
+    FProjectData := OpenProjectManager.FindProjectData(ASubTenderID);
+    try
+      if not Assigned(FProjectData) then
+      begin
+        FProjectData := TProjectData.Create;
+        FProjectData.OpenForSumUpGather(GetMyProjectsFilePath + vNode.Rec.ValueByName('FileName').AsString);
+      end;
+      FCacheData.AddSubTender(vNode.Rec);
+      GatherSubTenderTreeNode(FProjectData.BillsMeasureData.BillsMeasureTree.FirstNode, nil);
+    finally
+      if not Assigned(OpenProjectManager.FindProjectData(ASubTenderID)) then
+        FProjectData.Free;
+    end;
+  end;
+end;
+
+procedure TstgSubTenderFileGather.GatherSubTenderTreeNode(
+  ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
+var
+  vCur: TstgGatherTreeNode;
+begin
+  if not Assigned(ANode) then Exit;
+  vCur := GatherSubTenderTreeNodeData(ANode, AParent);
+  GatherSubTenderTreeNode(ANode.FirstChild, vCur);
+  GatherSubTenderTreeNode(ANode.NextSibling, AParent);
+end;
+
+function TstgSubTenderFileGather.GatherSubTenderTreeNodeData(
+  ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
+var
+  vNode: TMeasureBillsIDTreeNode;
+  vNext: TstgGatherTreeNode;
+begin
+  vNode := TMeasureBillsIDTreeNode(ANode);
+  if ANode.ID < 100 then
+    Result := FCacheData.GatherTree.FindNode(ANode.ID)
+  else
+    Result := FCacheData.GatherTree.FindNode(AParent, vNode);
+
+  if not Assigned(Result) then
+  begin
+    vNext := FCacheData.GatherTree.FindNextSibling(AParent, vNode.Rec.Code.AsString, vNode.Rec.B_Code.AsString);
+    if not Assigned(AParent) or (not (AParent.IsSumBase and AParent.IsLeafXmj)) or (vNode.Rec.B_Code.AsString <> '') {or (not ANode.HasChildren)} then
+    begin
+      if ANode.ID < 100 then
+        Result := FCacheData.GatherTree.AddSubTenderNode(AParent, vNext, ANode.ID)
+      else
+        Result := FCacheData.GatherTree.AddSubTenderNode(AParent, vNext);
+      Result.Code := Trim(vNode.Rec.Code.AsString);
+      Result.B_Code := Trim(vNode.Rec.B_Code.AsString);
+      Result.Name := Trim(vNode.Rec.Name.AsString);
+      Result.Units := Trim(vNode.Rec.Units.AsString);
+      Result.IsLeaf := not vNode.HasChildren;
+    end
+    else
+      Result := AParent;
+  end;
+
+  if Assigned(Result) then
+    GatherDetailData(Result, vNode)
+  else
+    Result := AParent;
+end;
+
+procedure TstgSubTenderFileGather.GatherTo(AGatherCacheData: TstgGatherCacheData;
+  ASubTenders: TList);
+var
+  i, iSubTenderID: Integer;
+begin
+  FCacheData := AGatherCacheData;
+  for i := 0 to ASubTenders.Count - 1 do
+    GatherSubTender(Integer(ASubTenders.Items[i]));
+  FCacheData.GatherTree.CalculateAll;
+end;
+
+{ TstgErrorChecker }
+
+procedure TstgErrorChecker.AddError(ANode: TstgGatherTreeNode);
+begin
+  if ANode.IsGclBills then
+    AddGclError(ANode)
+  else
+    AddXmjError(ANode);
+end;
+
+procedure TstgErrorChecker.AddGclError(ANode: TstgGatherTreeNode);
+begin
+  if HasXmjChildWithSameCodeChild(ANode) then
+    NewError(ANode, iErrorXmjLess)
+  else if HasLongRelaCodeChild(ANode) then
+    NewError(ANode, iErrorGclMore)
+  else if HasShortRelaCodeChild(ANode) then
+    NewError(ANode, iErrorGclLess)
+  else if HasSameChildWithDiffLevel(ANode) then
+    NewError(ANode, iErrorGclMore)
+  else if HasSameCodeLevelChild(ANode) then
+    NewError(ANode, iErrorGclDiff)
+  else
+    NewError(ANode, iErrorGclAdd);
+end;
+
+procedure TstgErrorChecker.AddXmjError(ANode: TstgGatherTreeNode);
+begin
+  if HasSameCodeLevelChild(ANode) then
+    NewError(ANode, iErrorXmjDiff)
+  else
+    NewError(ANode, iErrorXmjAdd);
+end;
+
+procedure TstgErrorChecker.Check(AGatherCacheData: TstgGatherCacheData);
+var
+  i: Integer;
+  vNode, vParent: TstgGatherTreeNode;
+begin
+  FCacheData := AGatherCacheData;
+  for i := 0 to FCacheData.GatherTree.CacheNodes.Count - 1 do
+  begin
+    vNode := TstgGatherTreeNode(FCacheData.GatherTree.CacheNodes[i]);
+    vParent := TstgGatherTreeNode(vNode.Parent);
+    if vNode.IsSubTender and (not Assigned(vParent) or not vParent.IsSubTender) then
+      AddError(vNode);
+  end;
+end;
+
+function TstgErrorChecker.HasLongRelaCodeChild(
+  ANode: TstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, nil);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if (Pos(ANode.B_Code + '-', vChild.B_Code) = 1) and (vChild.IsSumBase) then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function TstgErrorChecker.HasSameChildWithDiffLevel(ANode,
+  ACheckParent: TstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, ACheckParent);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if vChild.IsSumBase and (vChild.Code = ANode.Code) and
+       (vChild.B_Code = ANode.B_Code) and (vChild.Name = ANode.Name) and
+       (vChild.Units = ANode.Units) and (vChild.IsLeaf = vChild.IsLeaf) then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function TstgErrorChecker.HasSameCodeLevelChild(ANode,
+  ACheckParent: tstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, ACheckParent);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if vChild.IsSumBase and (vChild.Code = ANode.Code) and (vChild.B_Code = ANode.B_Code) and (vChild.IsLeaf = vChild.IsLeaf) then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function TstgErrorChecker.HasShortRelaCodeChild(
+  ANode: TstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, nil);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if (Pos(vChild.B_Code + '-', ANode.B_Code) = 1) and (vChild.IsSumBase) then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function TstgErrorChecker.HasXmjChildWithSameCodeChild(
+  ANode: TstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, nil);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if not vChild.IsGclBills and ANode.IsGclBills and vChild.IsSumBase then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+procedure TstgErrorChecker.NewError(ANode: TstgGatherTreeNode;
+  AType: Integer);
+
+  procedure RecursiveNewError(AParent: TstgGatherTreeNode);
+  var
+    i: Integer;
+  begin
+    if AParent.Children.Count > 0 then
+    begin
+      for i := 0 to AParent.Children.Count - 1 do
+        RecursiveNewError(TstgGatherTreeNode(AParent.Children.Items[i]));
+    end
+    else
+      FCacheData.AddError(ANode, AParent, AType);
+  end;
+
+begin
+  RecursiveNewError(ANode);
+end;
+
+function TstgErrorChecker.SafeCheckParent(ANode,
+  ACheckParent: TstgGatherTreeNode): TstgGatherTreeNode;
+begin
+  if Assigned(ACheckParent) then
+    Result := ACheckParent
+  else if Assigned(ANode.Parent) then
+    Result := TstgGatherTreeNode(ANode.Parent)
+  else
+    Result := TstgGatherTreeNode(FCacheData.GatherTree.Root);
+end;
+
+end.

+ 738 - 0
SubTenderGather/stgGatherCacheData.pas

@@ -0,0 +1,738 @@
+unit stgGatherCacheData;
+
+interface
+
+uses
+  CacheTree, SysUtils, BillsTree, Classes, sdDB, mDataRecord;
+
+const
+  // 新增项目节
+  iErrorXmjAdd = 1;
+  sErrorXmjAdd = '新增';
+  // 存在同号项目节,但名称、单价不同
+  iErrorXmjDiff = 2;    
+  sErrorXmjDiff = '存在同号不同名(单位)';
+  // 项目节层次少于总包
+  iErrorXmjLess = 3;
+  sErrorXmjLess = '父项项目节,层次少于总包';
+
+  // 新增工程量清单
+  iErrorGclAdd = 11;
+  sErrorGclAdd = '新增';
+  // 存在同名工程量清单,但名称、单价不同
+  iErrorGclDiff = 12;   
+  sErrorGclDiff = '存在同号不同名(单位)';
+  // 工程量清单层次多于总包
+  iErrorGclMore = 13;
+  sErrorGclMore = '工程量清单,层次多于总包';
+  // 工程量清单层次少于总包
+  iErrorGclLess = 14;
+  sErrorGclLess = '工程量清单,层次少于总包';
+
+type
+  TstgStageData = class
+  private
+    FDealQuantity: Double;
+    FDealTotalPrice: Double;
+    FQcQuantity: Double;
+    FQcTotalPrice: Double;
+    FQcBGLCode: string;
+    FQcBGLNum: string;
+
+    procedure AddBGLCodeAndNum(ACode, ANum: string);
+  public
+    procedure ClearData;
+    procedure AddStageData(AStageData: TstgStageData);
+    procedure AssignedData(AStageRecord: TStageRecord);
+
+    property DealQuantity: Double read FDealQuantity;
+    property DealTotalPrice: Double read FDealTotalPrice;
+    property QcQuantity: Double read FQcQuantity;
+    property QcTotalPrice: Double read FQcTotalPrice;
+    property QcBGLCode: string read FQcBGLCode;
+    property QcBGLNum: string read FQcBGLNum;
+  end;
+
+  TstgSubTenderDetailData = class
+  private
+    FSerialNo: Integer;
+    FLeafXmjCode: string;
+    FDetailStage: TstgStageData;
+  public
+    constructor Create(ANode: TMeasureBillsIDTreeNode);
+    destructor Destroy; override;
+
+    property SerialNo: Integer read FSerialNo;
+    property LeafXmjCode: string read FLeafXmjCode;
+    property DetailStage: TstgStageData read FDetailStage;
+  end;
+
+  TstgSubTenderStageData = class
+  private
+    FSubTenderID: Integer;
+    FGather: TstgStageData;
+    FDetails: TList;
+    function GetDetail(AIndex: Integer): TstgSubTenderDetailData;
+    function GetDetailCount: Integer;
+  public
+    constructor Create(ASubTenderID: Integer);
+    destructor Destroy; override;
+
+    function AddDetail(ANode: TMeasureBillsIDTreeNode): TstgSubTenderDetailData;
+
+    procedure CalculateGather;
+
+    property SubTenderID: Integer read FSubTenderID;
+    property Gather: TstgStageData read FGather;
+    property DetailCount: Integer read GetDetailCount;
+    property Detail[AIndex: Integer]: TstgSubTenderDetailData read GetDetail;
+  end;
+
+  TstgGatherTreeNode = class(TCacheNode)
+  private
+    FCode: string;
+    FB_Code: string;
+    FName: string;
+    FUnits: string;
+
+    FIsSumBase: Boolean;
+    FIsLeafXmj: Boolean;
+    FIsLeaf: Boolean;
+    FIsSubTender: Boolean;
+
+    FGather: TstgStageData;
+    FSubTenders: TList;
+    function GetIsGclBills: Boolean;
+    function GetSubTender(AIndex: Integer): TstgSubTenderStageData;
+    function GetSubTenderCount: Integer;
+  public
+    constructor Create(ATree: TCacheTree; AID: Integer); override;
+    destructor Destroy; override;
+
+    function FindSubTender(ASubTenderID: Integer): TstgSubTenderStageData;
+    function SafeSubTender(ASubTenderID: Integer): TstgSubTenderStageData;
+
+    procedure CalculateGather;
+
+    property Code: string read FCode write FCode;
+    property B_Code: string read FB_Code write FB_Code;
+    property Name: string read FName write FName;
+    property Units: string read FUnits write FUnits;
+
+    property IsSumBase: Boolean read FIsSumBase write FIsSumBase;
+    property IsLeafXmj: Boolean read FIsLeafXmj write FIsLeafXmj;
+    property IsLeaf: Boolean read FIsLeaf write FIsLeaf;
+    property IsSubTender: Boolean read FIsSubTender write FIsSubTender;
+
+    property IsGclBills: Boolean read GetIsGclBills;
+
+    property SubTenderCount: Integer read GetSubTenderCount;
+    property SubTender[AIndex: Integer]: TstgSubTenderStageData read GetSubTender;
+
+    property Gather: TstgStageData read FGather;
+  end;
+
+  TstgGatherTree = class(TCacheTree)
+  private
+    FFixedNodes: TCacheNodeList;
+    // -1的情况下默认自动赋值一个新的ID
+    function GetNewNode(AID: Integer = -1): TstgGatherTreeNode; overload;
+
+    function CheckLeafXmj(ANode: TstgGatherTreeNode): Boolean;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+
+    function FindNextSibling(AParent: TCacheNode; ACode, AB_Code: string): TstgGatherTreeNode;
+    function FindNode(AParent: TCacheNode; AInfo: TBillsIDTreeNode): TstgGatherTreeNode; overload;
+    function FindNode(AID: Integer): TstgGatherTreeNode; overload;
+
+    function AddFixedNode(AParent: TCacheNode; ANextSibling:
+      TCacheNode = nil; AFixedID: Integer = -1): TstgGatherTreeNode;
+    function AddNode(AParent: TCacheNode; ANextSibling:
+      TCacheNode = nil; ASumBaseID: Integer = -1): TstgGatherTreeNode;
+
+    function AddSumBaseNode(AParent: TCacheNode; ASumBaseID: Integer): TstgGatherTreeNode;
+    function AddSubTenderNode(AParent: TCacheNode; ANextSibling: TCacheNode; AFixedID: Integer = -1): TstgGatherTreeNode;
+
+    // Only for Debugging lot of Data
+    procedure SaveTreeToFile(const AFileName: string);
+
+    procedure MarkLeafXmj;
+    procedure CalculateAll;
+  end;
+
+  TstgGatherSubTender = class
+  private
+    FID: Integer;
+    FRec: TsdDataRecord;
+  public
+    constructor Create(ARec: TsdDataRecord);
+
+    property ID: Integer read FID;
+    property Rec: TsdDataRecord read FRec;
+  end;
+
+  TstgErrorInfo = class
+  private
+    FRelaNode: TstgGatherTreeNode;
+    FErrorType: Integer;
+
+    FDetails: TList;
+    function GetDetail(AIndex: Integer): TstgGatherTreeNode;
+    function GetDetailCount: Integer;
+  public
+    constructor Create(ARelaNode: TstgGatherTreeNode);
+    destructor Destroy; override;
+
+    procedure AddErrorDetail(ARelaDetailNode: TstgGatherTreeNode);
+
+    property RelaNode: TstgGatherTreeNode read FRelaNode;
+    property ErrorType: Integer read FErrorType write FErrorType;
+
+    property DetailCount: Integer read GetDetailCount;
+    property Detail[AIndex: Integer]: TstgGatherTreeNode read GetDetail;
+  end;
+
+  TstgGatherCacheData = class
+  private
+    FGatherTree: TstgGatherTree;
+    FSubTenders: TList;
+    FErrors: TList;
+
+    function FindError(ANode: TstgGatherTreeNode): TstgErrorInfo;
+    function NewError(ANode: TstgGatherTreeNode; AErrorType: Integer): TstgErrorInfo;
+
+    function GetSubTenderCount: Integer;
+    function GetSubTender(AIndex: Integer): TstgGatherSubTender;
+    function GetErrorCount: Integer;
+    function GetError(AIndex: Integer): TstgErrorInfo;
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function FindSubTender(AID: Integer): TstgGatherSubTender;
+    function AddSubTender(ARec: TsdDataRecord): TstgGatherSubTender;
+
+    procedure AddError(ANode, ALeafErrorNode: TstgGatherTreeNode; AErrorType: Integer);
+
+    property SubTenderCount: Integer read GetSubTenderCount;
+    property SubTender[AIndex: Integer]: TstgGatherSubTender read GetSubTender;
+
+    property ErrorCount: Integer read GetErrorCount;
+    property Error[AIndex: Integer]: TstgErrorInfo read GetError;
+
+    property GatherTree: TstgGatherTree read FGatherTree;
+  end;
+
+implementation
+
+uses
+  ZhAPI, UtilMethods, Math;
+
+{ TstgGatherTreeNode }
+
+procedure TstgGatherTreeNode.CalculateGather;
+var
+  i: Integer;
+  vSubTender: TstgSubTenderDetailData;
+begin
+  FGather.ClearData;
+  for i := 0 to FSubTenders.Count - 1 do
+  begin
+    SubTender[i].CalculateGather;
+    FGather.AddStageData(SubTender[i].Gather);
+  end;
+end;
+
+constructor TstgGatherTreeNode.Create(ATree: TCacheTree; AID: Integer);
+begin
+  inherited Create(ATree, AID);
+  FSubTenders := TList.Create;
+  FGather := TstgStageData.Create;
+end;
+
+destructor TstgGatherTreeNode.Destroy;
+begin
+  FGather.Free;
+  ClearObjects(FSubTenders);
+  FSubTenders.Free;
+  inherited;
+end;
+
+function TstgGatherTreeNode.FindSubTender(
+  ASubTenderID: Integer): TstgSubTenderStageData;
+var
+  i: Integer;
+begin
+  Result := nil;
+  for i := 0 to FSubTenders.Count - 1 do
+  begin
+    if ASubTenderID = SubTender[i].SubTenderID then
+    begin
+      Result := SubTender[i];
+      Break;
+    end;
+  end;
+end;
+
+function TstgGatherTreeNode.GetIsGclBills: Boolean;
+begin
+  Result := FB_Code <> '';
+end;
+
+function TstgGatherTreeNode.GetSubTender(
+  AIndex: Integer): TstgSubTenderStageData;
+begin
+  Result := TstgSubTenderStageData(FSubTenders.Items[AIndex]);
+end;
+
+function TstgGatherTreeNode.GetSubTenderCount: Integer;
+begin
+  Result := FSubTenders.Count;
+end;
+
+function TstgGatherTreeNode.SafeSubTender(
+  ASubTenderID: Integer): TstgSubTenderStageData;
+begin
+  Result := FindSubTender(ASubTenderID);
+  if not Assigned(Result) then
+  begin
+    Result := TstgSubTenderStageData.Create(ASubTenderID);
+    FSubTenders.Add(Result);
+  end;
+end;
+
+{ TstgGatherTree }
+
+function TstgGatherTree.AddFixedNode(AParent, ANextSibling: TCacheNode;
+  AFixedID: Integer): TstgGatherTreeNode;
+begin
+  Result := GetNewNode(AFixedID);
+  if Assigned(ANextSibling) then
+    ANextSibling.InsertPreSibling(Result)
+  else if Assigned(AParent) then
+    AParent.InsertChild(Result)
+  else
+    Root.InsertChild(Result);
+  FFixedNodes.Add(Result);
+end;
+
+function TstgGatherTree.AddNode(AParent, ANextSibling: TCacheNode;
+  ASumBaseID: Integer): TstgGatherTreeNode;
+begin
+  Result := GetNewNode(ASumBaseID);
+  if Assigned(ANextSibling) then
+    ANextSibling.InsertPreSibling(Result)
+  else if Assigned(AParent) then
+    AParent.InsertChild(Result)
+  else
+    Root.InsertChild(Result);
+end;
+
+function TstgGatherTree.AddSubTenderNode(AParent, ANextSibling: TCacheNode;
+  AFixedID: Integer): TstgGatherTreeNode;
+begin
+  Result := GetNewNode(AFixedID);
+  Result.IsSubTender := True;
+
+  if Assigned(ANextSibling) then
+    ANextSibling.InsertPreSibling(Result)
+  else if Assigned(AParent) then
+    AParent.InsertChild(Result)
+  else
+    Root.InsertChild(Result);
+end;
+
+function TstgGatherTree.AddSumBaseNode(AParent: TCacheNode;
+  ASumBaseID: Integer): TstgGatherTreeNode;
+begin
+  Result := GetNewNode(ASumBaseID);
+  Result.IsSumBase := True;
+
+  if Assigned(AParent) then
+    AParent.InsertChild(Result)
+  else
+    Root.InsertChild(Result);
+end;
+
+procedure TstgGatherTree.CalculateAll;
+var
+  i: Integer;
+begin
+  for i := 0 to CacheNodes.Count - 1 do
+    TstgGatherTreeNode(CacheNodes[i]).CalculateGather;
+end;
+
+function TstgGatherTree.CheckLeafXmj(ANode: TstgGatherTreeNode): Boolean;
+var
+  iChild: Integer;
+  vChild: TstgGatherTreeNode;
+begin
+  Result := True;
+  for iChild := 0 to ANode.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(ANode.Children.Items[iChild]);
+    if vChild.FB_Code = '' then
+    begin
+      Result := False;
+      Break;
+    end;
+  end;
+end;
+
+constructor TstgGatherTree.Create;
+begin
+  inherited;
+  FFixedNodes := TCacheNodeList.Create;
+  NewNodeID := 100;
+end;
+
+destructor TstgGatherTree.Destroy;
+begin
+  FFixedNodes.Free;
+  inherited;
+end;
+
+function TstgGatherTree.FindNextSibling(AParent: TCacheNode;
+  ACode, AB_Code: string): TstgGatherTreeNode;
+var
+  vChild: TstgGatherTreeNode;
+begin
+  Result := nil;
+  if Assigned(AParent) then
+    vChild := TstgGatherTreeNode(AParent.FirstChild)
+  else
+    vChild := TstgGatherTreeNode(Root.FirstChild);
+  while not Assigned(Result) and Assigned(vChild) do
+  begin
+    if (CompareCode(ACode, vChild.Code) < 0) or (CompareCode(AB_Code, vChild.B_Code) < 0) then
+      Result := vChild;
+    vChild := TstgGatherTreeNode(vChild.NextSibling);
+  end;
+end;
+
+function TstgGatherTree.FindNode(AID: Integer): TstgGatherTreeNode;
+var
+  i: Integer;
+  Node: TCacheNode;
+begin
+  Result := nil;
+  for i := 0 to FFixedNodes.Count - 1 do
+  begin
+    Node := FFixedNodes.Items[i];
+    if Node.ID = AID then
+    begin
+      Result := TstgGatherTreeNode(Node);
+      Break;
+    end;
+  end;
+end;
+
+function TstgGatherTree.FindNode(AParent: TCacheNode;
+  AInfo: TBillsIDTreeNode): TstgGatherTreeNode;
+var
+  vNode: TstgGatherTreeNode;
+begin
+  Result := nil;
+  if Assigned(AParent) then
+    vNode := TstgGatherTreeNode(AParent.FirstChild)
+  else
+    vNode := TstgGatherTreeNode(Root.FirstChild);
+
+  while Assigned(vNode) and not Assigned(Result) do
+  begin
+    if SameText(vNode.Code, Trim(AInfo.Rec.Code.AsString)) and SameText(vNode.B_Code, Trim(AInfo.Rec.B_Code.AsString))
+        and SameText(vNode.Name, Trim(AInfo.Rec.Name.AsString)) and SameText(vNode.Units, Trim(AInfo.Rec.Units.AsString))
+        and ((vNode.B_Code = '') or (vNode.IsLeaf = not AInfo.HasChildren)) then
+      Result := vNode;
+    vNode := TstgGatherTreeNode(vNode.NextSibling);
+  end;
+end;
+
+function TstgGatherTree.GetNewNode(AID: Integer): TstgGatherTreeNode;
+begin
+  if AID = -1 then
+    Result := TstgGatherTreeNode.Create(Self, GetNewNodeID)
+  else
+    Result := TstgGatherTreeNode.Create(Self, AID);
+  NewNodeID := Max(NewNodeID, AID + 1);
+  CacheNodes.Add(Result);
+  if AID < 100 then
+    FFixedNodes.Add(Result);
+end;
+
+procedure TstgGatherTree.MarkLeafXmj;
+var
+  i: Integer;
+  vNode: TstgGatherTreeNode;
+begin
+  for i := 0 to CacheNodes.Count - 1 do
+  begin
+    vNode := TstgGatherTreeNode(CacheNodes.Items[i]);
+    vNode.IsLeafXmj := CheckLeafXmj(vNode);
+  end;
+end;
+
+procedure TstgGatherTree.SaveTreeToFile(const AFileName: string);
+var
+  sgs: TStringList;
+  I: Integer;
+  Node: TstgGatherTreeNode;
+begin
+  sgs := TStringList.Create;
+  try
+    for I := 0 to CacheNodes.Count - 1 do
+    begin
+      Node := TstgGatherTreeNode(CacheNodes.Items[I]);
+      sgs.Add(Format('ID: %3d; ParentID: %3d; NextID: %3d; Code: %s; B_Code: %s; Name: %s;',
+        [Node.ID, Node.ParentID, Node.NextSiblingID, Node.Code, Node.B_Code, Node.Name]));
+    end;
+    sgs.SaveToFile(AFileName);
+  finally
+    sgs.Free;
+  end;
+end;
+
+{ TstgGatherCacheData }
+
+procedure TstgGatherCacheData.AddError(ANode,
+  ALeafErrorNode: TstgGatherTreeNode; AErrorType: Integer);
+var
+  vError: TstgErrorInfo;
+begin
+  vError := FindError(ANode);
+  if not Assigned(vError) then
+    vError := NewError(ANode, AErrorType);
+  vError.AddErrorDetail(ALeafErrorNode);
+end;
+
+function TstgGatherCacheData.AddSubTender(
+  ARec: TsdDataRecord): TstgGatherSubTender;
+begin
+  Result := FindSubTender(ARec.ValueByName('ID').AsInteger);
+  if not Assigned(Result) then
+  begin
+    Result := TstgGatherSubTender.Create(ARec);
+    FSubTenders.Add(Result);
+  end;
+end;
+
+constructor TstgGatherCacheData.Create;
+begin
+  FGatherTree := TstgGatherTree.Create;
+  FSubTenders := TList.Create;
+  FErrors := TList.Create;
+end;
+
+destructor TstgGatherCacheData.Destroy;
+begin
+  ClearObjects(FErrors);
+  FErrors.Free;
+  ClearObjects(FSubTenders);
+  FSubTenders.Free;
+  FGatherTree.Free;
+  inherited;
+end;
+
+function TstgGatherCacheData.FindError(
+  ANode: TstgGatherTreeNode): TstgErrorInfo;
+var
+  i: Integer;
+begin
+  Result := nil;
+  for i := 0 to ErrorCount - 1 do
+  begin
+    if Error[i].RelaNode = ANode then
+    begin
+      Result := Error[i];
+      Break;
+    end;
+  end;
+end;
+
+function TstgGatherCacheData.FindSubTender(
+  AID: Integer): TstgGatherSubTender;
+var
+  i: Integer;
+begin
+  Result := nil;
+  for i := 0 to SubTenderCount - 1 do
+  begin
+    if SubTender[i].ID = AID then
+    begin
+      Result := SubTender[i];
+      Break;
+    end;
+  end;
+end;
+
+function TstgGatherCacheData.GetError(AIndex: Integer): TstgErrorInfo;
+begin
+  Result := TstgErrorInfo(FErrors.Items[AIndex]);
+end;
+
+function TstgGatherCacheData.GetErrorCount: Integer;
+begin
+  Result := FErrors.Count;
+end;
+
+function TstgGatherCacheData.GetSubTender(AIndex: Integer): TstgGatherSubTender;
+begin
+  Result := TstgGatherSubTender(FSubTenders.Items[AIndex]);
+end;
+
+function TstgGatherCacheData.GetSubTenderCount: Integer;
+begin
+  Result := FSubTenders.Count;
+end;
+
+function TstgGatherCacheData.NewError(
+  ANode: TstgGatherTreeNode; AErrorType: Integer): TstgErrorInfo;
+begin
+  Result := TstgErrorInfo.Create(ANode);
+  Result.ErrorType := AErrorType;
+  FErrors.Add(Result);
+end;
+
+{ TstgGatherSubTender }
+
+constructor TstgGatherSubTender.Create(ARec: TsdDataRecord);
+begin
+  FID := ARec.ValueByName('ID').AsInteger;
+  FRec := ARec;
+end;
+
+{ TstgStageData }
+
+procedure TstgStageData.AddBGLCodeAndNum(ACode, ANum: string);
+var
+  sCode, sNum: string;
+begin
+  sCode := FQcBGLCode;
+  sNum := FQcBGLNum;
+  MergeRelaBGLAndNum(sCode, sNum, ACode, ANum);
+  FQcBGLCode := sCode;
+  FQcBGLNum := sNum;
+end;
+
+procedure TstgStageData.AddStageData(AStageData: TstgStageData);
+begin
+  FDealQuantity := FDealQuantity + AStageData.DealQuantity;
+  FDealTotalPrice := FDealTotalPrice + AStageData.DealTotalPrice;
+  FQcQuantity := FQcQuantity + AStageData.QcQuantity;
+  FQcTotalPrice := FQcTotalPrice + AStageData.QcTotalPrice;
+  AddBGLCodeAndNum(AStageData.QcBGLCode, AStageData.QcBGLNum);
+end;
+
+procedure TstgStageData.AssignedData(AStageRecord: TStageRecord);
+begin
+  FDealQuantity := AStageRecord.DealQuantity.AsFloat;
+  FDealTotalPrice := AStageRecord.DealTotalPrice.AsFloat;
+  FQcQuantity := AStageRecord.QcQuantity.AsFloat;
+  FQcTotalPrice := AStageRecord.QcTotalPrice.AsFloat;
+  FQcBGLCode := AStageRecord.QcBGLCode.AsString;
+  FQcBGLNum := AStageRecord.QcBGLNum.AsString;
+end;
+
+procedure TstgStageData.ClearData;
+begin
+  FDealQuantity := 0;
+  FDealTotalPrice := 0;
+  FQcQuantity := 0;
+  FQcTotalPrice := 0;
+  FQcBGLCode := '';
+  FQcBGLNum := '';
+end;
+
+{ TstgSubTenderStageData }
+
+function TstgSubTenderStageData.AddDetail(
+  ANode: TMeasureBillsIDTreeNode): TstgSubTenderDetailData;
+begin
+  Result := TstgSubTenderDetailData.Create(ANode);
+  FDetails.Add(Result);
+end;
+
+procedure TstgSubTenderStageData.CalculateGather;
+var
+  i: Integer;
+begin
+  FGather.ClearData;
+  for i := 0 to DetailCount - 1 do
+    FGather.AddStageData(Detail[i].DetailStage);
+end;
+
+constructor TstgSubTenderStageData.Create(ASubTenderID: Integer);
+begin
+  FSubTenderID := ASubTenderID;
+  FGather := TstgStageData.Create;
+  FDetails := TList.Create;
+end;
+
+destructor TstgSubTenderStageData.Destroy;
+begin
+  ClearObjects(FDetails);
+  FDetails.Free;
+  FGather.Free;
+  inherited;
+end;
+
+function TstgSubTenderStageData.GetDetail(
+  AIndex: Integer): TstgSubTenderDetailData;
+begin
+  Result := TstgSubTenderDetailData(FDetails.Items[AIndex]);
+end;
+
+function TstgSubTenderStageData.GetDetailCount: Integer;
+begin
+  Result := FDetails.Count;
+end;
+
+{ TstgSubTenderDetailData }
+
+constructor TstgSubTenderDetailData.Create(ANode: TMeasureBillsIDTreeNode);
+begin
+  FSerialNo := ANode.MajorIndex + 1;
+  FDetailStage := TstgStageData.Create;
+  if Assigned(ANode.StageRec) then
+    FDetailStage.AssignedData(ANode.StageRec);
+end;
+
+destructor TstgSubTenderDetailData.Destroy;
+begin
+  FDetailStage.Free;
+  inherited;
+end;
+
+{ TstgErrorInfo }
+
+procedure TstgErrorInfo.AddErrorDetail(
+  ARelaDetailNode: TstgGatherTreeNode);
+begin
+  FDetails.Add(ARelaDetailNode);
+end;
+
+constructor TstgErrorInfo.Create(ARelaNode: TstgGatherTreeNode);
+begin
+  FRelaNode := ARelaNode;
+  FDetails := TList.Create;
+end;
+
+destructor TstgErrorInfo.Destroy;
+begin
+  FDetails.Free;
+  inherited;
+end;
+
+function TstgErrorInfo.GetDetail(AIndex: Integer): TstgGatherTreeNode;
+begin
+  Result :=  TstgGatherTreeNode(FDetails.Items[AIndex]);
+end;
+
+function TstgErrorInfo.GetDetailCount: Integer;
+begin
+  Result := FDetails.Count;
+end;
+
+end.

+ 137 - 0
SubTenderGather/stgGatherControl.pas

@@ -0,0 +1,137 @@
+unit stgGatherControl;
+
+interface
+
+uses
+  Classes, stgGatherCacheData, stgGatherDm, stgResultFrm,
+  stgGather;
+
+type
+  TstgGatherControl = class
+  private
+    FProjects: TList;
+    FSumBaseFile: string;
+
+    FGatherCacheData: tstgGatherCacheData;
+    FGatherData: TstgGatherData;
+    FResultForm: TstgResultForm;
+
+    FHintPosition: Integer;
+
+    procedure LoadHint(const ATenderName: string);
+
+    procedure LoadSumBaseFile;
+    procedure GatherSubTenderFiles;
+    procedure CheckErrorData;
+    procedure SaveGatherResult;
+    procedure ShowGatherResult;
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    procedure Gather;
+
+    property Projects: TList read FProjects;
+    property SumBaseFile: string read FSumBaseFile write FSumBaseFile;
+  end;
+
+implementation
+
+uses
+  ProgressHintFrm, SysUtils;
+
+{ TstgGatherControl }
+
+procedure TstgGatherControl.CheckErrorData;
+var
+  vChecker: TstgErrorChecker;
+begin
+  vChecker := TstgErrorChecker.Create;
+  try
+    vChecker.Check(FGatherCacheData);
+  finally
+    vChecker.Free;
+  end;
+end;
+
+constructor TstgGatherControl.Create;
+begin
+  FProjects := TList.Create;
+  FGatherCacheData := TstgGatherCacheData.Create;
+  FGatherData := TstgGatherData.Create(nil);
+end;
+
+destructor TstgGatherControl.Destroy;
+begin
+  FGatherData.Free;
+  FGatherCacheData.Free;
+  FProjects.Free;
+  inherited;
+end;
+
+procedure TstgGatherControl.Gather;
+begin
+  FHintPosition := 0;
+  ShowProgressHint('正在导入总包基准文件数据...', FProjects.Count + 2);
+  LoadSumBaseFile;
+  GatherSubTenderFiles;
+  UpdateProgressHint('正在检查汇总结果...');
+  UpdateProgressPosition(FProjects.Count + 1);
+  CheckErrorData;
+  UpdateProgressPosition(FProjects.Count + 2);
+  SaveGatherResult;
+  CloseProgressHint;
+  ShowGatherResult;
+end;
+
+procedure TstgGatherControl.GatherSubTenderFiles;
+var
+  vGather: TstgSubTenderFileGather;
+begin
+  vGather := TstgSubTenderFileGather.Create;
+  try
+    vGather.LoadHint := LoadHint;
+    vGather.GatherTo(FGatherCacheData, FProjects);
+  finally
+    vGather.Free;
+  end;
+end;
+
+procedure TstgGatherControl.LoadHint(const ATenderName: string);
+begin
+  Inc(FHintPosition);
+  UpdateProgressHint(Format('正在汇总分包标段"%s"...', [ATenderName]));
+  UpdateProgressPosition(FHintPosition);
+end;
+
+procedure TstgGatherControl.LoadSumBaseFile;
+var
+  vLoader: TstgSumBaseFileLoader;
+begin
+  vLoader := TstgSumBaseFileLoader.Create(FGatherCacheData.GatherTree, FSumBaseFile);
+  try
+    vLoader.LoadData;
+  finally
+    vLoader.Free;
+  end;
+end;
+
+procedure TstgGatherControl.SaveGatherResult;
+begin
+  FGatherData.LoadGatherData(FGatherCacheData);
+end;
+
+procedure TstgGatherControl.ShowGatherResult; 
+var
+  Form: TstgResultForm;
+begin
+  Form := TstgResultForm.Create(nil);
+  try
+    Form.SetGatherData(FGatherData);
+    Form.ShowModal;
+  finally
+    Form.Free;
+  end;
+end;
+
+end.

+ 304 - 0
SubTenderGather/stgGatherDm.dfm

@@ -0,0 +1,304 @@
+object stgGatherData: TstgGatherData
+  OldCreateOrder = False
+  Left = 37
+  Top = 195
+  Height = 253
+  Width = 482
+  object smpGatherTree: TsdMemoryProvider
+    Left = 40
+    Top = 24
+  end
+  object sddGatherTree: TsdDataSet
+    Active = True
+    Provider = smpGatherTree
+    Left = 40
+    Top = 87
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650809507265636973696F6E02000453697A6502000001044E616D
+      650608506172656E744944094669656C644E616D650608506172656E74494408
+      44617461547970650203084461746153697A6502040549734B6579080F4E6565
+      6450726F636573734E616D650809507265636973696F6E02000453697A650200
+      0001044E616D65060D4E6578745369626C696E674944094669656C644E616D65
+      060D4E6578745369626C696E6749440844617461547970650203084461746153
+      697A6502040549734B6579080F4E65656450726F636573734E616D6508095072
+      65636973696F6E02000453697A6502000001044E616D650604436F6465094669
+      656C644E616D650604436F64650844617461547970650218084461746153697A
+      6502320549734B6579080F4E65656450726F636573734E616D65080950726563
+      6973696F6E02000453697A6502000001044E616D650606425F436F6465094669
+      656C644E616D650606425F436F64650844617461547970650218084461746153
+      697A6502320549734B6579080F4E65656450726F636573734E616D6508095072
+      65636973696F6E02000453697A6502000001044E616D6506044E616D65094669
+      656C644E616D6506044E616D650844617461547970650218084461746153697A
+      6503FF000549734B6579080F4E65656450726F636573734E616D650809507265
+      636973696F6E02000453697A6502000001044E616D650605556E697473094669
+      656C644E616D650605556E697473084461746154797065021808446174615369
+      7A6502140549734B6579080F4E65656450726F636573734E616D650809507265
+      636973696F6E02000453697A6502000001044E616D65060C4465616C5175616E
+      74697479094669656C644E616D65060C4465616C5175616E7469747908446174
+      61547970650206084461746153697A6502080549734B6579080F4E6565645072
+      6F636573734E616D650809507265636973696F6E02000453697A650200000104
+      4E616D65060A51635175616E74697479094669656C644E616D65060A51635175
+      616E746974790844617461547970650206084461746153697A6502080549734B
+      6579080F4E65656450726F636573734E616D650809507265636973696F6E0200
+      0453697A6502000001044E616D65060B497353756254656E646572094669656C
+      644E616D65060B497353756254656E6465720844617461547970650205084461
+      746153697A6502010549734B6579080F4E65656450726F636573734E616D6508
+      09507265636973696F6E02000453697A6502000001044E616D65060E4465616C
+      546F74616C5072696365094669656C644E616D65060E4465616C546F74616C50
+      726963650844617461547970650206084461746153697A6502080549734B6579
+      080F4E65656450726F636573734E616D650809507265636973696F6E02000453
+      697A6502000001044E616D65060C5163546F74616C5072696365094669656C64
+      4E616D65060C5163546F74616C50726963650844617461547970650206084461
+      746153697A6502080549734B6579080F4E65656450726F636573734E616D6508
+      09507265636973696F6E02000453697A6502000001044E616D65060951634247
+      4C436F6465094669656C644E616D650609516342474C436F6465084461746154
+      7970650218084461746153697A6503FF000549734B6579080F4E65656450726F
+      636573734E616D650809507265636973696F6E02000453697A6502000001044E
+      616D650608516342474C4E756D094669656C644E616D650608516342474C4E75
+      6D0844617461547970650218084461746153697A6503FF000549734B6579080F
+      4E65656450726F636573734E616D650809507265636973696F6E02000453697A
+      6502000001044E616D650609497353756D42617365094669656C644E616D6506
+      09497353756D426173650844617461547970650205084461746153697A650201
+      0549734B6579080F4E65656450726F636573734E616D65080950726563697369
+      6F6E02000453697A6502000001044E616D65060649734C656166094669656C64
+      4E616D65060649734C6561660844617461547970650205084461746153697A65
+      02010549734B6579080F4E65656450726F636573734E616D6508095072656369
+      73696F6E02000453697A6502000000}
+  end
+  object sdvGatherTree: TsdDataView
+    Active = False
+    DataSet = sddGatherTree
+    Filtered = False
+    Columns = <
+      item
+        FieldName = 'ID'
+      end
+      item
+        FieldName = 'ParentID'
+      end
+      item
+        FieldName = 'NextSiblingID'
+      end
+      item
+        FieldName = 'Code'
+      end
+      item
+        FieldName = 'B_Code'
+      end
+      item
+        FieldName = 'Name'
+      end
+      item
+        FieldName = 'Units'
+      end
+      item
+        FieldName = 'DealQuantity'
+      end
+      item
+        FieldName = 'QcQuantity'
+      end>
+    OnCurrentChanged = sdvGatherTreeCurrentChanged
+    OnGetText = sdvGatherTreeGetText
+    Left = 40
+    Top = 152
+  end
+  object smpSubTenders: TsdMemoryProvider
+    Left = 136
+    Top = 24
+  end
+  object sddSubTenders: TsdDataSet
+    Active = True
+    Provider = smpSubTenders
+    Left = 136
+    Top = 88
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650809507265636973696F6E02000453697A6502000001044E616D
+      6506044E616D65094669656C644E616D6506044E616D65084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650809507265636973696F6E02000453697A6502000000}
+  end
+  object sdvSubTenders: TsdDataView
+    Active = True
+    DataSet = sddSubTenders
+    Filtered = False
+    Columns = <
+      item
+        FieldName = 'ID'
+      end
+      item
+        FieldName = 'Name'
+      end
+      item
+        FieldName = 'ErrorCount'
+      end>
+    OnCurrentChanged = sdvSubTendersCurrentChanged
+    Left = 136
+    Top = 152
+  end
+  object smpBillsDetail: TsdMemoryProvider
+    Left = 248
+    Top = 24
+  end
+  object sddBillsDetail: TsdDataSet
+    Active = True
+    Provider = smpBillsDetail
+    Left = 248
+    Top = 88
+    FieldListData = {
+      0101044E616D65060742696C6C734944094669656C644E616D65060742696C6C
+      7349440844617461547970650203084461746153697A6502040549734B657908
+      0F4E65656450726F636573734E616D650809507265636973696F6E0200045369
+      7A6502000001044E616D65060854656E6465724944094669656C644E616D6506
+      0854656E64657249440844617461547970650203084461746153697A65020405
+      49734B6579080F4E65656450726F636573734E616D650809507265636973696F
+      6E02000453697A6502000001044E616D65060A54656E6465724E616D65094669
+      656C644E616D65060A54656E6465724E616D6508446174615479706502180844
+      61746153697A6503FF000549734B6579080F4E65656450726F636573734E616D
+      650809507265636973696F6E02000453697A6502000001044E616D6506085365
+      7269616C4E6F094669656C644E616D65060853657269616C4E6F084461746154
+      7970650203084461746153697A6502040549734B6579080F4E65656450726F63
+      6573734E616D650809507265636973696F6E02000453697A6502000001044E61
+      6D65060C4465616C5175616E74697479094669656C644E616D65060C4465616C
+      5175616E746974790844617461547970650206084461746153697A6502080549
+      734B6579080F4E65656450726F636573734E616D650809507265636973696F6E
+      02000453697A6502000001044E616D65060E4465616C546F74616C5072696365
+      094669656C644E616D65060E4465616C546F74616C5072696365084461746154
+      7970650206084461746153697A6502080549734B6579080F4E65656450726F63
+      6573734E616D650809507265636973696F6E02000453697A6502000001044E61
+      6D65060A51635175616E74697479094669656C644E616D65060A51635175616E
+      746974790844617461547970650206084461746153697A6502080549734B6579
+      080F4E65656450726F636573734E616D650809507265636973696F6E02000453
+      697A6502000001044E616D65060C5163546F74616C5072696365094669656C64
+      4E616D65060C5163546F74616C50726963650844617461547970650206084461
+      746153697A6502080549734B6579080F4E65656450726F636573734E616D6508
+      09507265636973696F6E02000453697A6502000001044E616D65060951634247
+      4C436F6465094669656C644E616D650609516342474C436F6465084461746154
+      7970650218084461746153697A6503FF000549734B6579080F4E65656450726F
+      636573734E616D650809507265636973696F6E02000453697A6502000001044E
+      616D650608516342474C4E756D094669656C644E616D650608516342474C4E75
+      6D0844617461547970650218084461746153697A6503FF000549734B6579080F
+      4E65656450726F636573734E616D650809507265636973696F6E02000453697A
+      6502000000}
+  end
+  object sdvBillsDetail: TsdDataView
+    Active = False
+    DataSet = sddBillsDetail
+    Filtered = True
+    Columns = <
+      item
+        FieldName = 'BillsID'
+      end
+      item
+        FieldName = 'TenderID'
+      end
+      item
+        FieldName = 'TenderName'
+      end
+      item
+        FieldName = 'SerialNo'
+      end
+      item
+        FieldName = 'DealQuantity'
+      end
+      item
+        FieldName = 'DealTotalPrice'
+      end
+      item
+        FieldName = 'QcQuantity'
+      end
+      item
+        FieldName = 'QcTotalPrice'
+      end
+      item
+        FieldName = 'QcBGLCode'
+      end
+      item
+        FieldName = 'QcBGLNum'
+      end
+      item
+      end>
+    OnFilterRecord = sdvBillsDetailFilterRecord
+    OnGetText = sdvBillsDetailGetText
+    Left = 248
+    Top = 152
+  end
+  object sdmErrorDetail: TsdMemoryProvider
+    Left = 352
+    Top = 24
+  end
+  object sddErrorDetail: TsdDataSet
+    Active = True
+    Provider = sdmErrorDetail
+    Left = 352
+    Top = 88
+    FieldListData = {
+      0101044E616D65060854656E6465724944094669656C644E616D65060854656E
+      64657249440844617461547970650203084461746153697A6502040549734B65
+      79080F4E65656450726F636573734E616D650809507265636973696F6E020004
+      53697A6502000001044E616D65060A54656E6465724E616D65094669656C644E
+      616D65060A54656E6465724E616D650844617461547970650218084461746153
+      697A6503FF000549734B6579080F4E65656450726F636573734E616D65080950
+      7265636973696F6E02000453697A6502000001044E616D65060852656C61436F
+      6465094669656C644E616D65060852656C61436F646508446174615479706502
+      18084461746153697A6502320549734B6579080F4E65656450726F636573734E
+      616D650809507265636973696F6E02000453697A6502000001044E616D65060C
+      52656C6153657269616C4E6F094669656C644E616D65060C52656C6153657269
+      616C4E6F0844617461547970650203084461746153697A6502040549734B6579
+      080F4E65656450726F636573734E616D650809507265636973696F6E02000453
+      697A6502000001044E616D65060A44657461696C436F6465094669656C644E61
+      6D65060A44657461696C436F6465084461746154797065021808446174615369
+      7A6502320549734B6579080F4E65656450726F636573734E616D650809507265
+      636973696F6E02000453697A6502000001044E616D65060E44657461696C5365
+      7269616C4E6F094669656C644E616D65060E44657461696C53657269616C4E6F
+      0844617461547970650203084461746153697A6502040549734B6579080F4E65
+      656450726F636573734E616D650809507265636973696F6E02000453697A6502
+      000001044E616D6506094572726F7254797065094669656C644E616D65060945
+      72726F72547970650844617461547970650203084461746153697A6502040549
+      734B6579080F4E65656450726F636573734E616D650809507265636973696F6E
+      02000453697A6502000000}
+    IndexListData = {
+      01044E616D65060B69647854656E64657249440A4669656C644E616D65730608
+      54656E64657249440000}
+  end
+  object sdvErrorDetail: TsdDataView
+    Active = False
+    DataSet = sddErrorDetail
+    Filtered = False
+    Columns = <
+      item
+        FieldName = 'TenderID'
+      end
+      item
+        FieldName = 'TenderName'
+      end
+      item
+        FieldName = 'RelaID'
+      end
+      item
+        FieldName = 'RelaCode'
+      end
+      item
+        FieldName = 'RelaSerialNo'
+      end
+      item
+        FieldName = 'DetailID'
+      end
+      item
+        FieldName = 'DetailCode'
+      end
+      item
+        FieldName = 'DetailSerialNo'
+      end
+      item
+        FieldName = 'ErrorType'
+      end>
+    OnFilterRecord = sdvErrorDetailFilterRecord
+    OnGetText = sdvErrorDetailGetText
+    Left = 352
+    Top = 152
+  end
+end

+ 281 - 0
SubTenderGather/stgGatherDm.pas

@@ -0,0 +1,281 @@
+unit stgGatherDm;
+// ½á¹ûչʾ£¬ÄÚ´æ±í
+
+interface
+
+uses
+  SysUtils, Classes, stgGatherCacheData, sdDB, sdProvider, stgGatherUtils;
+
+type
+  TstgGatherData = class(TDataModule)
+    smpGatherTree: TsdMemoryProvider;
+    sddGatherTree: TsdDataSet;
+    sdvGatherTree: TsdDataView;
+    smpSubTenders: TsdMemoryProvider;
+    sddSubTenders: TsdDataSet;
+    sdvSubTenders: TsdDataView;
+    smpBillsDetail: TsdMemoryProvider;
+    sddBillsDetail: TsdDataSet;
+    sdvBillsDetail: TsdDataView;
+    sdmErrorDetail: TsdMemoryProvider;
+    sddErrorDetail: TsdDataSet;
+    sdvErrorDetail: TsdDataView;
+    procedure sdvBillsDetailGetText(var Text: String;
+      ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+      DisplayText: Boolean);
+    procedure sdvBillsDetailFilterRecord(ARecord: TsdDataRecord;
+      var Allow: Boolean);
+    procedure sdvGatherTreeCurrentChanged(ARecord: TsdDataRecord);
+    procedure sdvGatherTreeGetText(var Text: String;
+      ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+      DisplayText: Boolean);
+    procedure sdvErrorDetailFilterRecord(ARecord: TsdDataRecord;
+      var Allow: Boolean);
+    procedure sdvSubTendersCurrentChanged(ARecord: TsdDataRecord);
+    procedure sdvErrorDetailGetText(var Text: String;
+      ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+      DisplayText: Boolean);
+  private
+    procedure LoadSubTenders(ACacheData: TstgGatherCacheData);
+
+    procedure LoadGatherTreeNodeDetail(ANode: TstgGatherTreeNode);
+    procedure LoadGatherTreeNode(ANode: TstgGatherTreeNode);
+    procedure LoadGatherTree(ACacheData: TstgGatherCacheData);
+
+    procedure LoadError(AError: TstgErrorInfo);
+    procedure LoadErrors(ACacheData: TstgGatherCacheData);
+  public
+    procedure LoadGatherData(ACacheData: TstgGatherCacheData);
+  end;
+
+implementation
+
+uses
+  Variants, DB, ConditionalDefines;
+
+{$R *.dfm}
+
+{ TstgGatherData }
+
+procedure TstgGatherData.LoadGatherData(ACacheData: TstgGatherCacheData);
+begin
+  LoadSubTenders(ACacheData);
+  LoadGatherTree(ACacheData);
+  LoadErrors(ACacheData);
+
+  sdvGatherTree.Active := True;
+  sdvBillsDetail.Active := True;
+  sdvBillsDetail.RefreshFilter;
+
+  sdvSubTenders.Active := True;
+  sdvErrorDetail.Active := True;
+  sdvErrorDetail.RefreshFilter;
+end;
+
+procedure TstgGatherData.LoadGatherTree(ACacheData: TstgGatherCacheData);
+var
+  i: Integer;
+  vNode:TstgGatherTreeNode;
+begin
+  if _IsDebugView then
+    ACacheData.GatherTree.SaveTreeToFile('E:\stgGatherTree.txt');
+  for i := 0 to ACacheData.GatherTree.CacheNodes.Count - 1 do
+  begin
+    vNode := TstgGatherTreeNode(ACacheData.GatherTree.CacheNodes.Items[i]);
+    LoadGatherTreeNode(vNode);
+  end;
+end;
+
+procedure TstgGatherData.LoadGatherTreeNode(ANode: TstgGatherTreeNode);
+var
+  Rec: TsdDataRecord;
+begin
+  Rec := sddGatherTree.Add;
+  Rec.ValueByName('ID').AsInteger := ANode.ID;
+  Rec.ValueByName('ParentID').AsInteger := ANode.ParentID;
+  Rec.ValueByName('NextSiblingID').AsInteger := ANode.NextSiblingID;
+  Rec.ValueByName('Code').AsString := ANode.Code;
+  Rec.ValueByName('B_Code').AsString := ANode.B_Code;
+  Rec.ValueByName('Name').AsString := ANode.Name;
+  Rec.ValueByName('Units').AsString := ANode.Units;
+  Rec.ValueByName('IsSubTender').AsBoolean := ANode.IsSubTender;
+  Rec.ValueByName('IsSumBase').AsBoolean := ANode.IsSumBase;
+  Rec.ValueByName('IsLeaf').AsBoolean := ANode.IsLeaf;
+
+  Rec.ValueByName('DealQuantity').AsFloat := ANode.Gather.DealQuantity;
+  Rec.ValueByName('DealTotalPrice').AsFloat := ANode.Gather.DealTotalPrice;
+  Rec.ValueByName('QcQuantity').AsFloat := ANode.Gather.QcQuantity;
+  Rec.ValueByName('QcTotalPrice').AsFloat := ANode.Gather.QcTotalPrice;
+  Rec.ValueByName('QcBGLCode').AsString := ANode.Gather.QcBGLCode;
+  Rec.ValueByName('QcBGLNum').AsString := ANode.Gather.QcBGLNum;
+  if ANode.Children.Count = 0 then
+    LoadGatherTreeNodeDetail(ANode);
+end;
+
+procedure TstgGatherData.LoadGatherTreeNodeDetail(
+  ANode: TstgGatherTreeNode);
+var
+  iSub, iDetail: Integer;
+  vSub: TstgSubTenderStageData;
+  vDetail: TstgSubTenderDetailData;
+  Rec: TsdDataRecord;
+  sSubTenderName: string;
+begin
+  for iSub := 0 to ANode.SubTenderCount - 1 do
+  begin
+    vSub := ANode.SubTender[iSub];
+    for iDetail := 0 to vSub.DetailCount - 1 do
+    begin
+      vDetail := vSub.Detail[iDetail];
+      Rec := sddBillsDetail.Add;
+      Rec.ValueByName('BillsID').AsInteger := ANode.ID;
+      Rec.ValueByName('TenderID').AsInteger := vSub.SubTenderID;
+      Rec.ValueByName('TenderName').AsString := '';
+      Rec.ValueByName('SerialNo').AsInteger := vDetail.SerialNo;
+      Rec.ValueByName('DealQuantity').AsFloat := vDetail.DetailStage.DealQuantity;
+      Rec.ValueByName('DealTotalPrice').AsFloat := vDetail.DetailStage.DealTotalPrice;
+      Rec.ValueByName('QcQuantity').AsFloat := vDetail.DetailStage.QcQuantity;
+      Rec.ValueByName('QcTotalPrice').AsFloat := vDetail.DetailStage.QcTotalPrice;
+      Rec.ValueByName('QcBGLCode').AsString := vDetail.DetailStage.QcBGLCode;
+      Rec.ValueByName('QcBGLNum').AsString := vDetail.DetailStage.QcBGLNum;
+    end;
+  end;
+end;
+
+procedure TstgGatherData.LoadSubTenders(ACacheData: TstgGatherCacheData);
+var
+  i: Integer;
+  vSubTender: TstgGatherSubTender;
+  Rec: TsdDataRecord;
+begin
+  for i := 0 to ACacheData.SubTenderCount - 1 do
+  begin
+    vSubTender := ACacheData.SubTender[i];
+    Rec := sddSubTenders.Add;
+    Rec.ValueByName('ID').AsInteger := vSubTender.ID;
+    Rec.ValueByName('Name').AsString := vSubTender.Rec.ValueByName('Name').AsString;
+  end;
+end;
+
+procedure TstgGatherData.sdvBillsDetailGetText(var Text: String;
+  ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+  DisplayText: Boolean);
+
+  function GetTenderName(ATenderID: Integer): string;
+  begin
+    Result := VarToStrDef(sddSubTenders.Lookup('ID', ATenderID, 'Name'), '');
+  end;
+
+begin
+  if DisplayText and (AColumn.FieldName = 'TenderName') then
+    Text := GetTenderName(ARecord.ValueByName('TenderID').asInteger);
+end;
+
+procedure TstgGatherData.sdvBillsDetailFilterRecord(ARecord: TsdDataRecord;
+  var Allow: Boolean);
+begin
+  if Assigned(sdvGatherTree.Current) then
+    Allow := ARecord.ValueByName('BillsID').AsInteger = sdvGatherTree.Current.ValueByName('ID').AsInteger
+  else
+    Allow := False;
+end;
+
+procedure TstgGatherData.sdvGatherTreeCurrentChanged(
+  ARecord: TsdDataRecord);
+begin
+  sdvBillsDetail.RefreshFilter;
+end;
+
+procedure TstgGatherData.sdvGatherTreeGetText(var Text: String;
+  ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+  DisplayText: Boolean);
+begin
+  if (AValue.DataType = ftFloat) and (AValue.AsFloat = 0) then
+  begin
+    Text := '';
+  end;
+end;
+
+procedure TstgGatherData.LoadErrors(ACacheData: TstgGatherCacheData);
+var
+  i: Integer;
+begin
+  for i := 0 to ACacheData.ErrorCount - 1 do
+    LoadError(ACacheData.Error[i]);
+end;
+
+procedure TstgGatherData.sdvErrorDetailFilterRecord(ARecord: TsdDataRecord;
+  var Allow: Boolean);
+begin
+  if Assigned(sdvSubTenders.Current) then
+    Allow := ARecord.ValueByName('TenderID').AsInteger = sdvSubTenders.Current.ValueByName('ID').AsInteger
+  else
+    Allow := False;
+end;
+
+procedure TstgGatherData.LoadError(AError: TstgErrorInfo);
+
+  function GetSubTenderSerialNo(ANode: TstgGatherTreeNode; ATenderID: Integer): Integer;
+  var
+    vSource: TstgSubTenderStageData;
+  begin
+    vSource := ANode.FindSubTender(ATenderID);
+    if Assigned(vSource) then
+      Result := vSource.Detail[0].SerialNo;
+  end;
+
+var
+  i, j, k: Integer;
+  vRelaDetail: TstgGatherTreeNode;
+  vRelaDetailStage: TstgSubTenderStageData;
+  Rec: TsdDataRecord;
+begin
+  for i := 0 to AError.DetailCount - 1 do
+  begin
+    vRelaDetail := AError.Detail[i];
+    for j := 0 to vRelaDetail.SubTenderCount - 1 do
+    begin
+      vRelaDetailStage := vRelaDetail.SubTender[j];
+      for k := 0 to vRelaDetailStage.DetailCount - 1 do
+      begin
+        Rec := sddErrorDetail.Add;
+        Rec.ValueByName('TenderID').AsInteger := vRelaDetail.SubTender[j].SubTenderID;
+        Rec.ValueByName('RelaCode').AsString := AError.RelaNode.Code + AError.RelaNode.B_Code;
+        if AError.RelaNode.IsLeaf then
+          Rec.ValueByName('RelaSerialNo').AsInteger := vRelaDetailStage.Detail[k].SerialNo
+        else
+          Rec.ValueByName('RelaSerialNo').AsInteger := GetSubTenderSerialNo(AError.RelaNode, vRelaDetailStage.SubTenderID);
+        Rec.ValueByName('DetailCode').AsString := vRelaDetail.Code + vRelaDetail.B_Code;
+        Rec.ValueByName('DetailSerialNo').AsInteger := vRelaDetailStage.Detail[k].SerialNo;
+        Rec.ValueByName('ErrorType').AsInteger := AError.ErrorType;
+      end;
+    end;
+  end;
+end;
+
+procedure TstgGatherData.sdvSubTendersCurrentChanged(
+  ARecord: TsdDataRecord);
+begin
+  sdvErrorDetail.RefreshFilter;
+end;
+
+procedure TstgGatherData.sdvErrorDetailGetText(var Text: String;
+  ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+  DisplayText: Boolean);
+
+  function GetTenderName(ATenderID: Integer): string;
+  begin
+    Result := VarToStrDef(sddSubTenders.Lookup('ID', ATenderID, 'Name'), '');
+  end;
+
+begin
+  if DisplayText then
+  begin
+    if (AColumn.FieldName = 'TenderName') then
+      Text := GetTenderName(ARecord.ValueByName('TenderID').asInteger)
+    else if (AColumn.FieldName = 'ErrorType') then
+      Text := GetErrorTypeText(AValue.AsInteger);
+  end;
+end;
+
+end.

+ 25 - 0
SubTenderGather/stgGatherUtils.pas

@@ -0,0 +1,25 @@
+unit stgGatherUtils;
+
+interface
+
+uses
+  stgGatherCacheData;
+
+  function GetErrorTypeText(AErrorType: Integer): string;
+
+implementation
+
+function GetErrorTypeText(AErrorType: Integer): string;
+begin
+  case AErrorType of
+    iErrorXmjAdd: Result := sErrorXmjAdd;
+    iErrorXmjDiff: Result := sErrorXmjDiff;
+    iErrorXmjLess: Result := sErrorXmjLess;
+    iErrorGclAdd: Result := sErrorGclAdd;
+    iErrorGclDiff: Result := sErrorGclDiff;
+    iErrorGclMore: Result := sErrorGclMore;
+    iErrorGclLess: Result := sErrorGclLess;
+  end;
+end;
+
+end.

+ 664 - 0
SubTenderGather/stgResultFrm.dfm

@@ -0,0 +1,664 @@
+object stgResultForm: TstgResultForm
+  Left = 192
+  Top = 123
+  Width = 1305
+  Height = 675
+  ActiveControl = zgGatherTree
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = #20998#21253#27719#24635
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  PixelsPerInch = 96
+  TextHeight = 13
+  object jpsResult: TJimPages
+    Left = 0
+    Top = 22
+    Width = 1297
+    Height = 594
+    ActivePage = jpsResultBillsDetail
+    ActivePageIndex = 0
+    Align = alClient
+    Caption = 'jpsResult'
+    object jpsResultBillsDetail: TJimPage
+      Left = 0
+      Top = 0
+      Width = 1297
+      Height = 594
+      TabName = 'BillsDetail'
+      Caption = 'Tree'
+      object Splitter1: TSplitter
+        Left = 924
+        Top = 0
+        Height = 594
+        Align = alRight
+      end
+      object pnlGatherTree: TPanel
+        Left = 0
+        Top = 0
+        Width = 924
+        Height = 594
+        Align = alClient
+        BevelOuter = bvNone
+        TabOrder = 0
+        object zgGatherTree: TZJGrid
+          Left = 0
+          Top = 0
+          Width = 924
+          Height = 594
+          Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection, goShowTreeLine]
+          OptionsEx = []
+          ColCount = 7
+          ShowGridLine = False
+          DefaultColWidth = 73
+          DefaultFixedColWidth = 25
+          Selection.AlphaBlend = False
+          Selection.TransparentColor = False
+          FrozenCol = 0
+          FrozenRow = 0
+          OnCellGetColor = zgGatherTreeCellGetColor
+          OnMouseDown = zgGatherTreeMouseDown
+          Align = alClient
+        end
+      end
+      object pnlDetail: TPanel
+        Left = 927
+        Top = 0
+        Width = 370
+        Height = 594
+        Align = alRight
+        BevelOuter = bvNone
+        TabOrder = 1
+        object zgBillsDetail: TZJGrid
+          Left = 0
+          Top = 0
+          Width = 370
+          Height = 594
+          Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection]
+          OptionsEx = []
+          ShowGridLine = False
+          DefaultColWidth = 73
+          DefaultFixedColWidth = 25
+          Selection.AlphaBlend = False
+          Selection.TransparentColor = False
+          FrozenCol = 0
+          FrozenRow = 0
+          Align = alClient
+        end
+      end
+    end
+    object jpsResultErrorDetail: TJimPage
+      Left = 0
+      Top = 0
+      Width = 1297
+      Height = 594
+      TabName = 'ErrorDetail'
+      Caption = 'Main'
+      object pnlError: TPanel
+        Left = 0
+        Top = 0
+        Width = 1297
+        Height = 594
+        Align = alClient
+        BevelOuter = bvNone
+        TabOrder = 0
+        object Splitter2: TSplitter
+          Left = 440
+          Top = 0
+          Height = 594
+        end
+        object pnlErrorInfo: TPanel
+          Left = 0
+          Top = 0
+          Width = 440
+          Height = 594
+          Align = alLeft
+          BevelOuter = bvNone
+          TabOrder = 0
+          object zgErrorInfo: TZJGrid
+            Left = 0
+            Top = 0
+            Width = 440
+            Height = 594
+            Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection]
+            OptionsEx = []
+            ColCount = 3
+            ShowGridLine = False
+            DefaultColWidth = 73
+            DefaultFixedColWidth = 25
+            Selection.AlphaBlend = False
+            Selection.TransparentColor = False
+            FrozenCol = 0
+            FrozenRow = 0
+            OnMouseDown = zgErrorInfoMouseDown
+            Align = alClient
+          end
+        end
+        object pnlErrorDetail: TPanel
+          Left = 443
+          Top = 0
+          Width = 854
+          Height = 594
+          Align = alClient
+          BevelOuter = bvNone
+          TabOrder = 1
+          object zgErrorDetail: TZJGrid
+            Left = 0
+            Top = 0
+            Width = 854
+            Height = 594
+            Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection]
+            OptionsEx = []
+            ColCount = 6
+            RowCount = 6
+            FixedRowCount = 2
+            ShowGridLine = False
+            DefaultColWidth = 73
+            DefaultFixedColWidth = 25
+            Selection.AlphaBlend = False
+            Selection.TransparentColor = False
+            FrozenCol = 0
+            FrozenRow = 0
+            Align = alClient
+          end
+        end
+      end
+    end
+  end
+  object jtsGatherData: TJimTabSet
+    Left = 0
+    Top = 0
+    Width = 1297
+    Height = 22
+    Align = alTop
+    BackgroundColor = clGradientInactiveCaption
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -12
+    Font.Name = 'smartSimSun'
+    Font.Style = []
+    SelectedColor = clWhite
+    XPSelectedColor = clWhite
+    XPUnSelectedColor = 15200496
+    Tabs.Strings = (
+      #27719#24635#32467#26524
+      #38169#35823#21015#34920)
+    TabIndex = 0
+    TabPosition = jtpTop
+    TabStyle = tdsNew
+    UnselectedColor = 15200496
+    OnChange = jtsGatherDataChange
+  end
+  object pnlResult: TPanel
+    Left = 0
+    Top = 616
+    Width = 1297
+    Height = 28
+    Align = alBottom
+    BevelOuter = bvNone
+    TabOrder = 2
+    Visible = False
+    object lblResult: TLabel
+      Left = 4
+      Top = 8
+      Width = 692
+      Height = 13
+      Caption = #20849#27719#24635'3'#20010#26631#27573#25968#25454#65292#20849#27719#24635#24037#31243#37327#28165#21333'X'#26465#65292#20854#20013'Y'#26465#27491#30830#27719#24635#65292#35813#37096#20998#21487#27491#30830#23548#20837#24635#21253#65292#26410#27491#30830#27719#24635#28165#21333#21487#35265#28165#21333#26126#32454#20013#28784#33394#37096#20998
+    end
+  end
+  object saGatherTree: TsdGridTreeDBA
+    Columns = <
+      item
+        Title.Caption = #39033#30446#33410#32534#21495
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Code'
+        Width = 180
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #28165#21333#32534#21495
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'B_Code'
+        Width = 80
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21517#31216
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Name'
+        Width = 240
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21333#20301
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Units'
+        Width = 50
+        ReadOnly = False
+      end
+      item
+        Title.Caption = 'ID'
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'ID'
+        Visible = False
+        ReadOnly = False
+      end
+      item
+        Title.Caption = 'ParentID'
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'ParentID'
+        Visible = False
+        ReadOnly = False
+      end
+      item
+        Title.Caption = 'NextSiblingID'
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'NextSiblingID'
+        Visible = False
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21512#21516#35745#37327
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taRightJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'DealQuantity'
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #25968#37327#21464#26356#35745#37327
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taRightJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'QcQuantity'
+        ReadOnly = False
+      end>
+    Grid = zgGatherTree
+    ExtendRowCount = 0
+    Options = []
+    AutoExpand = True
+    KeyFieldName = 'ID'
+    ParentFieldName = 'ParentID'
+    NextSiblingFieldName = 'NextSiblingID'
+    TreeOptions = []
+    TopLevelBold = True
+    Left = 104
+    Top = 110
+  end
+  object sdBillsDetail: TsdGridDBA
+    Columns = <
+      item
+        Title.Caption = #26631#27573
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'TenderName'
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #20301#32622
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'SerialNo'
+        Width = 50
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21512#21516#35745#37327
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taRightJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'DealQuantity'
+        Width = 85
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #25968#37327#21464#26356#35745#37327
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taRightJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'QcQuantity'
+        Width = 85
+        ReadOnly = False
+      end>
+    Grid = zgBillsDetail
+    ExtendRowCount = 0
+    Options = []
+    Left = 157
+    Top = 110
+  end
+  object sdErrorInfo: TsdGridDBA
+    Columns = <
+      item
+        Title.Caption = #21517#31216
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Name'
+        Width = 300
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #26410#27491#30830#27719#24635
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'ErrorCount'
+        Width = 80
+        ReadOnly = False
+      end>
+    Grid = zgErrorInfo
+    ExtendRowCount = 0
+    Options = []
+    Left = 104
+    Top = 196
+  end
+  object sdErrorDetail: TsdGridDBA
+    Columns = <
+      item
+        Title.Caption = #20986#38169#28304'|'#32534#21495
+        Title.CaptionAcrossCols = '2'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'RelaCode'
+        ReadOnly = False
+      end
+      item
+        Title.Caption = '|'#20301#32622
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'RelaSerialNo'
+        Width = 50
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21487#35745#37327#28165#21333'|'#32534#21495
+        Title.CaptionAcrossCols = '2'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'DetailCode'
+        ReadOnly = False
+      end
+      item
+        Title.Caption = '|'#20301#32622
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'DetailSerialNo'
+        Width = 50
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #38169#35823#31867#22411
+        Title.CaptionAcrossCols = '1'
+        Title.CaptionAcrossRows = 2
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'ErrorType'
+        Width = 200
+        ReadOnly = False
+      end>
+    Grid = zgErrorDetail
+    ExtendRowCount = 0
+    Options = []
+    Left = 160
+    Top = 195
+  end
+  object dxpmError: TdxBarPopupMenu
+    BarManager = MainForm.dxBarManager
+    ItemLinks = <
+      item
+        Item = MainForm.dxbtnExportTenderError
+        Visible = True
+      end
+      item
+        Item = MainForm.dxbtnExportAllError
+        Visible = True
+      end>
+    UseOwnFont = False
+    OnPopup = dxpmErrorPopup
+    Left = 104
+    Top = 235
+  end
+  object dxpmGatherTree: TdxBarPopupMenu
+    BarManager = MainForm.dxBarManager
+    ItemLinks = <
+      item
+        Item = MainForm.dxbtnExportStgResult
+        Visible = True
+      end
+      item
+        Item = MainForm.dxbtnExportStgResultExcel
+        Visible = True
+      end>
+    UseOwnFont = False
+    OnPopup = dxpmGatherTreePopup
+    Left = 104
+    Top = 148
+  end
+  object alStgResult: TActionList
+    Images = MainForm.Images
+    Left = 256
+    Top = 110
+    object actnExportAllError: TAction
+      Caption = #23548#20986#20840#37096#38169#35823#20449#24687
+      ImageIndex = 13
+      OnExecute = actnExportAllErrorExecute
+    end
+    object actnExportTenderError: TAction
+      Caption = #23548#20986#21333#26631#27573#38169#35823#20449#24687
+      ImageIndex = 13
+      OnExecute = actnExportTenderErrorExecute
+    end
+    object actnExportStgResultExcel: TAction
+      Caption = #23548#20986#20998#21253#27719#24635#32467#26524
+      ImageIndex = 13
+      OnExecute = actnExportStgResultExcelExecute
+    end
+    object actnExportStgResult: TAction
+      Caption = #23548#20986#20998#21253#27719#24635#32467#26524
+      OnExecute = actnExportStgResultExecute
+    end
+  end
+end

+ 190 - 0
SubTenderGather/stgResultFrm.pas

@@ -0,0 +1,190 @@
+unit stgResultFrm;
+
+interface
+
+uses
+  stgGatherDm, sdIDTree, UtilMethods, stgExcelExport, stgSubGatherFile,
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, JimTabs, JimPages, sdGridDBA, sdGridTreeDBA, ZJGrid, ExtCtrls,
+  StdCtrls, dxBar, ActnList;
+
+type
+  TstgResultForm = class(TForm)
+    jpsResult: TJimPages;
+    jpsResultErrorDetail: TJimPage;
+    jpsResultBillsDetail: TJimPage;
+    jtsGatherData: TJimTabSet;
+    pnlGatherTree: TPanel;
+    zgGatherTree: TZJGrid;
+    saGatherTree: TsdGridTreeDBA;
+    pnlDetail: TPanel;
+    zgBillsDetail: TZJGrid;
+    Splitter1: TSplitter;
+    sdBillsDetail: TsdGridDBA;
+    pnlError: TPanel;
+    pnlErrorInfo: TPanel;
+    zgErrorInfo: TZJGrid;
+    sdErrorInfo: TsdGridDBA;
+    pnlResult: TPanel;
+    lblResult: TLabel;
+    Splitter2: TSplitter;
+    pnlErrorDetail: TPanel;
+    zgErrorDetail: TZJGrid;
+    sdErrorDetail: TsdGridDBA;
+    dxpmError: TdxBarPopupMenu;
+    dxpmGatherTree: TdxBarPopupMenu;
+    alStgResult: TActionList;
+    actnExportAllError: TAction;
+    actnExportTenderError: TAction;
+    actnExportStgResultExcel: TAction;
+    actnExportStgResult: TAction;
+    procedure jtsGatherDataChange(Sender: TObject; NewTab: Integer;
+      var AllowChange: Boolean);
+    procedure zgGatherTreeCellGetColor(Sender: TObject; ACoord: TPoint;
+      var AColor: TColor);
+    procedure zgErrorInfoMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure zgGatherTreeMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure dxpmErrorPopup(Sender: TObject);
+    procedure actnExportAllErrorExecute(Sender: TObject);
+    procedure actnExportTenderErrorExecute(Sender: TObject);
+    procedure dxpmGatherTreePopup(Sender: TObject);
+    procedure actnExportStgResultExcelExecute(Sender: TObject);
+    procedure actnExportStgResultExecute(Sender: TObject);
+  private
+    FGatherData: TstgGatherData;
+    FExcelExportor: TstgErrorExcelExport;
+    function GetExcelExportor: TstgErrorExcelExport;
+  public
+    destructor Destroy; override;
+
+    procedure SetGatherData(AGatherData: TstgGatherData);
+
+    property ExcelExportor: TstgErrorExcelExport read GetExcelExportor; 
+  end;
+
+implementation
+
+uses
+  MainFrm;
+
+{$R *.dfm}
+
+procedure TstgResultForm.jtsGatherDataChange(Sender: TObject;
+  NewTab: Integer; var AllowChange: Boolean);
+begin
+  jpsResult.ActivePageIndex := NewTab;
+end;
+
+procedure TstgResultForm.SetGatherData(AGatherData: TstgGatherData);
+begin
+  FGatherData := AGatherData;
+  saGatherTree.DataView := AGatherData.sdvGatherTree;
+  sdBillsDetail.DataView := AGatherData.sdvBillsDetail;
+  sdErrorInfo.DataView := AGatherData.sdvSubTenders;
+  sdErrorDetail.DataView := AGatherData.sdvErrorDetail;
+end;
+
+procedure TstgResultForm.zgGatherTreeCellGetColor(Sender: TObject;
+  ACoord: TPoint; var AColor: TColor);
+var
+  vNode: TsdIDTreeNode;
+begin
+  vNode := saGatherTree.IDTree.Items[ACoord.Y - zgGatherTree.FixedRowCount];
+  if Assigned(vNode) and vNode.Rec.ValueByName('IsSubTender').AsBoolean then
+    AColor := $00D5D5D5;
+end;
+
+procedure TstgResultForm.zgErrorInfoMouseDown(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+  if Button = mbRight then
+    dxpmError.PopupFromCursorPos;
+end;
+
+procedure TstgResultForm.zgGatherTreeMouseDown(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+  if Button = mbRight then
+    dxpmGatherTree.PopupFromCursorPos;
+end;
+
+procedure TstgResultForm.dxpmErrorPopup(Sender: TObject);
+begin
+  SetDxBtnAction(actnExportAllError, MainForm.dxbtnExportAllError);
+  SetDxBtnAction(actnExportTenderError, MainForm.dxbtnExportTenderError);
+end;
+
+procedure TstgResultForm.actnExportAllErrorExecute(Sender: TObject);
+var
+  sFileName: string;
+begin
+  if SaveExcelFile(sFileName) then
+    ExcelExportor.ExportAll(sFileName);
+end;
+
+procedure TstgResultForm.actnExportTenderErrorExecute(Sender: TObject);
+var
+  sFileName: string;
+begin
+  if SaveExcelFile(sFileName) then
+    ExcelExportor.ExportSubTender(sdErrorInfo.DataView.Current, sFileName);
+end;
+
+function TstgResultForm.GetExcelExportor: TstgErrorExcelExport;
+begin
+  if Assigned(FGatherData) then
+  begin
+    if not Assigned(FExcelExportor) then
+      FExcelExportor := TstgErrorExcelExport.Create(FGatherData);
+    Result := FExcelExportor;
+  end
+  else
+    ErrorMessage('当前无汇总数据,无法导出');
+end;
+
+destructor TstgResultForm.Destroy;
+begin
+  if Assigned(FExcelExportor) then
+    FExcelExportor.Free;
+  inherited;
+end;
+
+procedure TstgResultForm.dxpmGatherTreePopup(Sender: TObject);
+begin
+  SetDxBtnAction(actnExportStgResult, MainForm.dxbtnExportStgResult);
+  SetDxBtnAction(actnExportStgResultExcel, MainForm.dxbtnExportStgResultExcel);
+end;
+
+procedure TstgResultForm.actnExportStgResultExcelExecute(Sender: TObject);
+var
+  vExportor: TstgGatherExcelExport;
+  sFileName: string;
+begin
+  vExportor := TstgGatherExcelExport.Create(FGatherData);
+  try
+    if SaveExcelFile(sFileName) then
+      vExportor.ExportGather(sFileName);
+  finally
+    vExportor.Free;
+  end;
+end;
+
+procedure TstgResultForm.actnExportStgResultExecute(Sender: TObject);
+var
+  sFileName: string;
+  vExportor: TstgSubGatherFileExportor;
+begin
+  if SaveFile(sFileName, '.sgf') then
+  begin
+    vExportor := TstgSubGatherFileExportor.Create;
+    try
+      vExportor.ExportGatherDataTo(FGatherData, sFileName);
+    finally
+      vExportor.Free;
+    end;
+  end;
+end;
+
+end.

+ 258 - 0
SubTenderGather/stgSelectFileFrm.dfm

@@ -0,0 +1,258 @@
+object stgSelectFileForm: TstgSelectFileForm
+  Left = 443
+  Top = 206
+  Width = 910
+  Height = 533
+  Caption = #20998#21253#26631#27573#27719#24635
+  Color = clBtnFace
+  Font.Charset = ANSI_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -12
+  Font.Name = #23435#20307
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poDesktopCenter
+  PixelsPerInch = 96
+  TextHeight = 12
+  object pnlTop: TPanel
+    Left = 0
+    Top = 0
+    Width = 902
+    Height = 33
+    Align = alTop
+    BevelOuter = bvNone
+    TabOrder = 0
+    DesignSize = (
+      902
+      33)
+    object leSumBaseFile: TLabeledEdit
+      Left = 117
+      Top = 7
+      Width = 727
+      Height = 18
+      Anchors = [akLeft, akTop, akRight]
+      Ctl3D = False
+      EditLabel.Width = 108
+      EditLabel.Height = 12
+      EditLabel.Caption = #36873#25321#24635#21253#22522#20934#25991#20214#65306
+      LabelPosition = lpLeft
+      ParentCtl3D = False
+      TabOrder = 0
+    end
+    object btnSelectSbf: TButton
+      Left = 851
+      Top = 5
+      Width = 44
+      Height = 21
+      Anchors = [akTop, akRight]
+      Caption = '...'
+      TabOrder = 1
+      OnClick = btnSelectSbfClick
+    end
+  end
+  object pnlGatherFiles: TPanel
+    Left = 0
+    Top = 33
+    Width = 902
+    Height = 428
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 1
+    object pnlSelect: TPanel
+      Left = 0
+      Top = 0
+      Width = 450
+      Height = 428
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object zgTenderSelect: TZJGrid
+        Left = 0
+        Top = 19
+        Width = 450
+        Height = 409
+        Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection, goShowTreeLine]
+        OptionsEx = []
+        ColCount = 3
+        RowCount = 1
+        ShowGridLine = False
+        DefaultColWidth = 35
+        DefaultFixedColWidth = 25
+        DefaultFixedRowHeight = 22
+        Selection.AlphaBlend = False
+        Selection.TransparentColor = False
+        FrozenCol = 0
+        FrozenRow = 0
+        OnGetCellText = zgTenderSelectGetCellText
+        OnSetCellText = zgTenderSelectSetCellText
+        OnCellTextChanged = zgTenderSelectCellTextChanged
+        OnDrawCellText = zgTenderSelectDrawCellText
+        OnShowHint = zgTenderSelectShowHint
+        Align = alClient
+      end
+      object pnlSelectTitle: TPanel
+        Left = 0
+        Top = 0
+        Width = 450
+        Height = 19
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 1
+        object lblTenderList: TLabel
+          Left = 6
+          Top = 2
+          Width = 72
+          Height = 12
+          Caption = #21487#36873#39033#30446#21015#34920
+          Font.Charset = ANSI_CHARSET
+          Font.Color = clBlue
+          Font.Height = -12
+          Font.Name = #23435#20307
+          Font.Style = []
+          ParentFont = False
+        end
+      end
+    end
+    object pnlDivision: TPanel
+      Left = 450
+      Top = 0
+      Width = 3
+      Height = 428
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 1
+    end
+    object pnlResult: TPanel
+      Left = 453
+      Top = 0
+      Width = 449
+      Height = 428
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 2
+      object zgResult: TZJGrid
+        Left = 0
+        Top = 19
+        Width = 449
+        Height = 409
+        OptionsEx = []
+        ColCount = 2
+        RowCount = 2
+        ShowGridLine = False
+        DefaultColWidth = 365
+        DefaultFixedColWidth = 25
+        DefaultFixedRowHeight = 22
+        Selection.AlphaBlend = False
+        Selection.TransparentColor = False
+        FrozenCol = 0
+        FrozenRow = 0
+        Align = alClient
+      end
+      object pnlResultTitle: TPanel
+        Left = 0
+        Top = 0
+        Width = 449
+        Height = 19
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 1
+        object lblResultList: TLabel
+          Left = 3
+          Top = 2
+          Width = 72
+          Height = 12
+          Caption = #25152#36873#39033#30446#21015#34920
+          Font.Charset = ANSI_CHARSET
+          Font.Color = clBlue
+          Font.Height = -12
+          Font.Name = #23435#20307
+          Font.Style = []
+          ParentFont = False
+        end
+      end
+    end
+  end
+  object pnlBottom: TPanel
+    Left = 0
+    Top = 461
+    Width = 902
+    Height = 41
+    Align = alBottom
+    BevelOuter = bvNone
+    TabOrder = 2
+    DesignSize = (
+      902
+      41)
+    object btnOk: TButton
+      Left = 731
+      Top = 8
+      Width = 75
+      Height = 25
+      Anchors = [akTop, akRight]
+      Caption = #30830#23450
+      TabOrder = 0
+      OnClick = btnOkClick
+    end
+    object btnCancel: TButton
+      Left = 817
+      Top = 8
+      Width = 75
+      Height = 25
+      Anchors = [akTop, akRight]
+      Caption = #21462#28040
+      ModalResult = 2
+      TabOrder = 1
+    end
+  end
+  object stdTenderSelect: TsdGridTreeDBA
+    Columns = <
+      item
+        Title.Caption = #36873#25321
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        EditType = sgeCheckBox
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        Width = 30
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21517#31216
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Name'
+        Width = 365
+        ReadOnly = True
+      end>
+    Grid = zgTenderSelect
+    ExtendRowCount = 0
+    Options = [aoAllowEdit]
+    AutoExpand = True
+    TreeCellCol = 2
+    KeyFieldName = 'ID'
+    ParentFieldName = 'ParentID'
+    NextSiblingFieldName = 'NextSiblingID'
+    TreeOptions = []
+    TopLevelBold = True
+    Left = 124
+    Top = 177
+  end
+end

+ 320 - 0
SubTenderGather/stgSelectFileFrm.pas

@@ -0,0 +1,320 @@
+unit stgSelectFileFrm;
+
+interface
+
+uses
+  stgGatherControl,
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, ExtCtrls, sdGridDBA, sdGridTreeDBA, ZJGrid, sdIDTree;
+
+type
+  TstgSelectFileForm = class(TForm)
+    pnlTop: TPanel;
+    leSumBaseFile: TLabeledEdit;
+    btnSelectSbf: TButton;
+    pnlGatherFiles: TPanel;
+    pnlSelect: TPanel;
+    zgTenderSelect: TZJGrid;
+    pnlSelectTitle: TPanel;
+    lblTenderList: TLabel;
+    stdTenderSelect: TsdGridTreeDBA;
+    pnlDivision: TPanel;
+    pnlResult: TPanel;
+    zgResult: TZJGrid;
+    pnlResultTitle: TPanel;
+    lblResultList: TLabel;
+    pnlBottom: TPanel;
+    btnOk: TButton;
+    btnCancel: TButton;
+    procedure zgTenderSelectDrawCellText(ACanvas: TCanvas;
+      const ARect: TRect; const ACoord: TPoint; AGrid: TZJGrid;
+      const Text: String; var ADefaultDraw: Boolean);
+    procedure zgTenderSelectShowHint(var HintStr: String;
+      var CanShow: Boolean; var HintInfo: THintInfo; const ACoord: TPoint);
+    procedure zgTenderSelectSetCellText(Sender: TObject;
+      const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+    procedure zgTenderSelectGetCellText(Sender: TObject;
+      const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+    procedure zgTenderSelectCellTextChanged(Sender: TObject; Col,
+      Row: Integer);
+    procedure btnOkClick(Sender: TObject);
+    procedure btnSelectSbfClick(Sender: TObject);
+  private
+    FSelects: TList;
+
+    procedure AddRows(ANode: TsdIDTreeNode);
+    procedure RemoveRows(ANode: TsdIDTreeNode);
+
+    procedure InitResultGrid;
+    procedure AssignResultGrid;
+    procedure AssignResult;
+    function GetSelectCount: Integer;
+  public
+    constructor Create(AGatherControl: TstgGatherControl);
+    destructor Destroy; override;
+
+    procedure AssignSelect(AGatherControl: TstgGatherControl);
+    property SelectCount: Integer read GetSelectCount;
+  end;
+
+function SelectFileForSubTenderGather(AGatherControl: TstgGatherControl): Boolean;
+
+implementation
+
+uses MainFrm, Globals, UtilMethods;
+
+{$R *.dfm}
+
+function SelectFileForSubTenderGather(AGatherControl: TstgGatherControl): Boolean;
+var
+  vSelectFrm: TstgSelectFileForm;
+begin
+  vSelectFrm := TstgSelectFileForm.Create(AGatherControl);
+  try
+    Result := vSelectFrm.ShowModal = mrOk;
+    if Result then
+      vSelectFrm.AssignSelect(AGatherControl);
+  finally
+    vSelectFrm.Free;
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectDrawCellText(ACanvas: TCanvas;
+  const ARect: TRect; const ACoord: TPoint; AGrid: TZJGrid;
+  const Text: String; var ADefaultDraw: Boolean);
+
+  procedure GetBitmap(AImage: TBitmap);
+  begin
+    with stdTenderSelect.IDTree.Items[ACoord.Y - 1] do
+      if Rec.ValueByName('Type').AsInteger = 0 then
+        if Expanded and HasChildren then
+          MainForm.Images.GetBitmap(34, AImage)
+        else
+          MainForm.Images.GetBitmap(34, AImage)
+      else
+        MainForm.Images.GetBitmap(11, AImage);
+  end;
+
+const
+  rIconWidth = 16;
+  rIconHeight = 16;
+var
+  Img: TBitmap;
+  Cell: TZjCell;
+  rImg: TRect;
+begin
+ if (ACoord.X = 2) and (ACoord.Y > zgTenderSelect.FixedRowCount - 1) then
+  begin
+    Cell := zgTenderSelect.Cells[ACoord.X, ACoord.Y];
+    Img := TBitmap.Create;
+    try
+      GetBitmap(Img);
+      case Cell.Align of
+        gaTopLeft, gaTopCenter, gaTopRight:
+          rImg := Rect(ARect.Left + 2, ARect.Top, ARect.Left + rIconWidth, ARect.Top + rIconHeight);
+        gaCenterLeft, gaCenterCenter, gaCenterRight:
+          rImg := Rect(ARect.Left + 2, ARect.Top + (ARect.Bottom - ARect.Top - rIconHeight) div 2, ARect.Left + rIconWidth, ARect.Bottom - (ARect.Bottom - ARect.Top - rIconHeight) div 2);
+        gaBottomLeft, gaBottomCenter, gaBottomRight:
+          rImg := Rect(ARect.Left + 2, ARect.Bottom - rIconHeight, ARect.Left + rIconWidth, ARect.Bottom);
+      end;
+      ACanvas.StretchDraw(rImg, Img);
+      WriteText(ACanvas, Rect(ARect.Left + rIconWidth, ARect.Top, ARect.Right, ARect.Bottom)
+        , 2, 2, Text, Cell.Align, False);
+      ADefaultDraw := False;
+    finally
+      Img.Free;
+    end;
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectShowHint(var HintStr: String;
+  var CanShow: Boolean; var HintInfo: THintInfo; const ACoord: TPoint);
+var
+  vCell: TZjCell;
+  vNode: TsdIDTreeNode;
+  iLevelWidth: Integer;
+  rText: TRect;
+
+  procedure CalcTextRect(var R: TRect);
+  var
+    DC: HDC;
+    iTextHeight: Integer;
+  begin
+    DC := CreateCompatibleDC(0);
+    try
+      SelectObject(DC, vCell.Font.Handle);
+      iTextHeight := DrawText(DC, PChar(vCell.Text), Length(vCell.Text), R, DT_SINGLELINE or DT_VCenter
+        or DT_NOCLIP or DT_CALCRECT);
+    finally
+      DeleteDC(DC);
+    end;
+  end;
+
+begin
+  if ACoord.Y < 1 then Exit;
+
+  vCell := zgTenderSelect.Cells[ACoord.X, ACoord.Y];
+  with HintInfo do
+  begin
+    vNode := stdTenderSelect.IDTree.Items[ACoord.Y - 1];
+    if not Assigned(vNode) then Exit;
+    iLevelWidth := (vNode.Level + 1) * 20 + 16;
+
+    rText := CursorRect;
+    CalcTextRect(rText);
+    if (rText.Right - rText.Left + iLevelWidth > CursorRect.Right - CursorRect.Left) or
+      (rText.Right > ClientWidth) then
+    begin
+      CanShow := True;
+      HintStr := vCell.Text;
+      GetCursorPos(HintPos);
+    end;
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectSetCellText(Sender: TObject;
+  const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+var
+  stnNode: TsdIDTreeNode;
+begin
+  if ACoord.X = 1 then
+  begin
+    stnNode := stdTenderSelect.IDTree.Items[ACoord.Y - 1];
+    if Value = 'True' then
+      AddRows(stnNode)
+    else
+      RemoveRows(stnNode);
+    AssignResult;
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectGetCellText(Sender: TObject;
+  const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+var
+  stnNode: TsdIDTreeNode;
+begin
+  if ACoord.X = 1 then
+  begin
+    stnNode := stdTenderSelect.IDTree.Items[ACoord.Y - 1];
+    if Assigned(stnNode) and (FSelects.IndexOf(Pointer(stnNode.ID)) > -1) then
+      Value := 'True';
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectCellTextChanged(Sender: TObject;
+  Col, Row: Integer);
+begin
+  if (Col = 1) then
+    zgTenderSelect.InvalidateCol(1);
+end;
+
+procedure TstgSelectFileForm.AddRows(ANode: TsdIDTreeNode);
+var
+  iChild: Integer;
+begin
+  if not Assigned(ANode) then Exit;
+
+  if FSelects.IndexOf(Pointer(ANode.ID)) = -1 then
+    FSelects.Add(Pointer(ANode.ID));
+
+  if ANode.HasChildren then
+    for iChild := 0 to ANode.ChildCount - 1 do
+      AddRows(ANode.ChildNodes[iChild]);
+end;
+
+procedure TstgSelectFileForm.RemoveRows(ANode: TsdIDTreeNode);
+var
+  iChild: Integer;
+begin
+  if not Assigned(ANode) then Exit;
+
+  if FSelects.IndexOf(Pointer(ANode.ID)) > -1 then
+    FSelects.Remove(Pointer(ANode.ID));
+
+  if ANode.HasChildren then
+    for iChild := 0 to ANode.ChildCount - 1 do
+      RemoveRows(ANode.ChildNodes[iChild]);
+end;
+
+procedure TstgSelectFileForm.InitResultGrid;
+begin
+  zgResult.ColCount := 2;
+  zgResult.RowCount := 1;
+  zgResult.Cells[1, 0].Text := '所选项目';
+  zgResult.ColWidths[1] := 365;
+end;
+
+procedure TstgSelectFileForm.AssignResultGrid;
+var
+  i, iID: Integer;
+  vNode: TsdIDTreeNode;
+begin
+  for i := 0 to FSelects.Count - 1 do
+  begin
+    iID := Integer(FSelects.Items[i]);
+    vNode := stdTenderSelect.IDTree.FindNode(iID);
+    if vNode.Rec.ValueByName('Type').AsInteger = 1 then
+    begin
+      zgResult.RowCount := zgResult.RowCount + 1;
+      zgResult.Cells[1, zgResult.RowCount - 1].Text := vNode.Rec.ValueByName('Name').AsString;
+      zgResult.Cells[1, zgResult.RowCount - 1].Align := gaCenterLeft;
+      zgResult.Rows[zgResult.RowCount - 1].Data := vNode;
+    end;
+  end;
+end;
+
+procedure TstgSelectFileForm.AssignSelect(AGatherControl: TstgGatherControl);
+begin
+  AGatherControl.SumBaseFile := leSumBaseFile.Text;
+  AGatherControl.Projects.Assign(FSelects);
+end;
+
+constructor TstgSelectFileForm.Create(AGatherControl: TstgGatherControl);
+begin
+  inherited Create(nil);
+  stdTenderSelect.DataView := ProjectManager.sdvProjectsSpare;
+  FSelects := TList.Create;
+  FSelects.Assign(AGatherControl.Projects);
+  InitResultGrid;
+  leSumBaseFile.Text := AGatherControl.SumBaseFile;
+end;
+
+destructor TstgSelectFileForm.Destroy;
+begin
+  FSelects.Free;
+  inherited;
+end;
+
+procedure TstgSelectFileForm.AssignResult;
+begin
+  InitResultGrid;
+  AssignResultGrid;
+end;
+
+procedure TstgSelectFileForm.btnOkClick(Sender: TObject);
+begin
+  if (leSumBaseFile.Text = '') then
+    WarningMessage('请选择总包基准文件。', Handle)
+  else if not FileExists(leSumBaseFile.Text) then
+    WarningMessage('当前选择的总包基准文件不存在,请重新选择。', Handle)
+  else if SelectCount = 0 then
+    WarningMessage('请选择需要汇总的分包标段。', Handle)
+  else
+    ModalResult := mrOk;
+end;
+
+function TstgSelectFileForm.GetSelectCount: Integer;
+begin
+  Result := zgResult.RowCount - zgResult.FixedRowCount;
+end;
+
+procedure TstgSelectFileForm.btnSelectSbfClick(Sender: TObject);
+var
+  sFileName: string;
+begin
+  sFileName := leSumBaseFile.Text;
+  if SelectFile(sFileName, '.sbf') then
+    leSumBaseFile.Text := sFileName;
+end;
+
+end.

+ 214 - 0
SubTenderGather/stgSubGatherFile.pas

@@ -0,0 +1,214 @@
+unit stgSubGatherFile;
+// µ¼Èëµ¼³ö»ã×ܽá¹û
+
+interface
+
+uses
+  stgSubGatherFileDm, ADODB, sdDB, stgGatherDm, SysUtils, StageDm, mDataRecord;
+
+type
+  TstgSubGatherFileHelper = class
+  private
+    FTempFile: string;
+    FConnection: TADOConnection;
+    FGatherData: TstgSubGatherData;
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    procedure Open(const AFileName: string);
+    procedure Close;
+    procedure SaveTo(const AFileName: string);
+
+    property Connection: TADOConnection read FConnection;
+    property GatherData: TstgSubGatherData read FGatherData;
+  end;
+
+  TstgSubGatherFileExportor = class(TstgSubGatherFileHelper)
+  private
+    procedure LoadMemoryRecord(ARec: TsdDataRecord);
+    procedure LoadMemoryGatherData(AGatherData: TstgGatherData);
+  public
+    procedure ExportGatherDataTo(AGatherData:TstgGatherData; const AFileName: string);
+  end;
+
+  TstgSubGatherFileImportor = class(TstgSubGatherFileHelper)
+  private
+    procedure ClearOldData(AStageData: TStageData);
+    procedure ImportGatherData(AStageData: TStageData);
+  public
+    procedure ImportGatherDataTo(AStageData: TStageData; const AFileName: string);
+  end;
+
+implementation
+
+
+uses
+  UtilMethods, ZhAPI, Connections, stgTables, ScAutoUpdateUnit, Math;
+
+{ TstgSubGatherFileExportor }
+
+procedure TstgSubGatherFileExportor.ExportGatherDataTo(
+  AGatherData: TstgGatherData; const AFileName: string);
+begin
+  Open(GetEmptyDataBaseFileName);
+  try
+    LoadMemoryGatherData(AGatherData);
+  finally                             
+    SaveTo(AFileName);
+  end;
+end;
+
+procedure TstgSubGatherFileExportor.LoadMemoryRecord(ARec: TsdDataRecord);
+var
+  vRec: TsdDataRecord;
+begin
+  vRec := GatherData.sddBills.Add;
+  vRec.ValueByName('ID').AsInteger := ARec.ValueByName('ID').AsInteger;
+  vRec.ValueByName('ParentID').AsInteger := ARec.ValueByName('ParentID').AsInteger;
+  vRec.ValueByName('NextSiblingID').AsInteger := ARec.ValueByName('NextSiblingID').AsInteger;
+  vRec.ValueByName('Code').AsString := ARec.ValueByName('Code').AsString;
+  vRec.ValueByName('B_Code').AsString := ARec.ValueByName('B_Code').AsString;
+  vRec.ValueByName('Name').AsString := ARec.ValueByName('Name').AsString;
+  vRec.ValueByName('Units').AsString := ARec.ValueByName('Units').AsString;
+  vRec.ValueByName('IsSumBase').AsBoolean := ARec.ValueByName('IsSumBase').AsBoolean;
+  vRec.ValueByName('IsLeaf').AsBoolean := ARec.ValueByName('IsLeaf').AsBoolean;
+  vRec.ValueByName('DealQuantity').AsFloat := ARec.ValueByName('DealQuantity').AsFloat;
+  vRec.ValueByName('DealTotalPrice').AsFloat := ARec.ValueByName('DealTotalPrice').AsFloat;
+  vRec.ValueByName('QcQuantity').AsFloat := ARec.ValueByName('QcQuantity').AsFloat;
+  vRec.ValueByName('QcTotalPrice').AsFloat := ARec.ValueByName('QcTotalPrice').AsFloat;
+  vRec.ValueByName('QcBGLCode').AsString := ARec.ValueByName('QcBGLCode').AsString;
+  vRec.ValueByName('QcBGLNum').AsString := ARec.ValueByName('QcBGLNum').AsString;
+end;
+
+procedure TstgSubGatherFileExportor.LoadMemoryGatherData(
+  AGatherData: TstgGatherData);
+var
+  i: Integer;
+  vRec: TsdDataRecord;
+begin
+  GatherData.sddBills.BeginUpdate;
+  try
+    for i := 0 to AGatherData.sddGatherTree.RecordCount - 1 do
+    begin
+      vRec := AGatherData.sddGatherTree.Records[i];
+      LoadMemoryRecord(vRec);
+    end;
+  finally
+    GatherData.sddBills.EndUpdate;
+  end;
+end;
+
+{ TstgSubGatherFileHelper }
+
+procedure TstgSubGatherFileHelper.Close;
+begin
+  FConnection.Close;
+  if FileExists(FTempFile) then
+    DeleteFile(FTempFile);
+end;
+
+constructor TstgSubGatherFileHelper.Create;
+begin
+  FConnection := TADOConnection.Create(nil);
+  FConnection.LoginPrompt := False;
+  FGatherData := TstgSubGatherData.Create(nil);
+end;
+
+destructor TstgSubGatherFileHelper.Destroy;
+begin
+  Close;
+  FGatherData.Free;
+  FConnection.Free;
+  inherited;
+end;
+
+procedure TstgSubGatherFileHelper.Open(const AFileName: string);
+
+  procedure UpdateDataTables;
+  var
+    Updater: TScUpdater;
+  begin
+    Updater := TScUpdater.Create;
+    try
+      Updater.ForceUpdate := True;
+      Updater.Open('', FConnection, '', '');
+      Updater.AddTableDef(sStgBills, @tdStgBills, Length(tdStgBills), False, False);
+      Updater.ExcuteUpdate;
+    finally
+      Updater.Free;
+    end;
+  end;
+
+begin
+  FTempFile := GetTempFileName;
+  CopyFileOrFolder(AFileName, FTempFile);
+  FConnection.ConnectionString := Format(SAdoConnectStr, [FTempFile]);
+  FConnection.Open;
+  UpdateDataTables;
+  GatherData.Open(FConnection);
+end;
+
+procedure TstgSubGatherFileHelper.SaveTo(const AFileName: string);
+begin
+  FGatherData.Save;
+  CopyFileOrFolder(FTempFile, AFileName);
+end;
+
+{ TstgSubGatherFileImportor }
+
+procedure TstgSubGatherFileImportor.ClearOldData(AStageData: TStageData);
+var
+  i: Integer;
+  vRec: TStageRecord;
+begin
+  for i := 0 to AStageData.sddStage.RecordCount - 1 do
+  begin
+    vRec := TStageRecord(AStageData.sddStage.Records[i]);
+    vRec.DealQuantity.AsFloat := 0;
+    vRec.DealTotalPrice.AsFloat := 0;
+    vRec.DealFlag.AsInteger := 0;
+    vRec.DealFormula.AsString := '';
+    vRec.QcQuantity.AsFloat := 0;
+    vRec.QcTotalPrice.AsFloat := 0;
+    vRec.QcFlag.AsInteger := 0;
+    vRec.QcFormula.AsString := '';
+    vRec.QcBGLCode.AsString := '';
+    vRec.QcBGLNum.AsString := '';
+  end;
+end;
+
+procedure TstgSubGatherFileImportor.ImportGatherData(
+  AStageData: TStageData);
+var
+  i: Integer;
+  vOrgRec: TsdDataRecord;
+  vStageRec: TStageRecord;
+begin
+  for i := 0 to GatherData.sddBills.RecordCount - 1 do
+  begin
+    vOrgRec := GatherData.sddBills.Records[i];
+    if vOrgRec.ValueByName('IsSumBase').AsBoolean and vOrgRec.ValueByName('IsLeaf').AsBoolean then
+    begin
+      vStageRec := AStageData.StageRecordWithAdd(vOrgRec.ValueByName('ID').AsInteger);
+      vStageRec.DealQuantity.AsFloat := vOrgRec.ValueByName('DealQuantity').AsFloat;
+    end;
+  end;
+end;
+
+procedure TstgSubGatherFileImportor.ImportGatherDataTo(
+  AStageData: TStageData; const AFileName: string);
+begin
+  Open(AFileName);
+  AStageData.sddStage.BeginUpdate;
+  AStageData.BeforeBatchOperation;
+  try
+    ClearOldData(AStageData);
+    ImportGatherData(AStageData);
+  finally
+    AStageData.AfterBatchOperation;
+    AStageData.sddStage.EndUpdate;
+  end;
+end;
+
+end.

+ 68 - 0
SubTenderGather/stgSubGatherFileDm.dfm

@@ -0,0 +1,68 @@
+object stgSubGatherData: TstgSubGatherData
+  OldCreateOrder = False
+  Left = 27
+  Top = 244
+  Height = 202
+  Width = 186
+  object sdpBills: TsdADOProvider
+    TableName = 'Bills'
+    Left = 35
+    Top = 32
+  end
+  object sddBills: TsdDataSet
+    Active = False
+    Provider = sdpBills
+    Left = 35
+    Top = 96
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650909507265636973696F6E02000453697A6502000001044E616D
+      650608506172656E744944094669656C644E616D650608506172656E74494408
+      44617461547970650203084461746153697A6502040549734B6579080F4E6565
+      6450726F636573734E616D650909507265636973696F6E02000453697A650200
+      0001044E616D65060D4E6578745369626C696E674944094669656C644E616D65
+      060D4E6578745369626C696E6749440844617461547970650203084461746153
+      697A6502040549734B6579080F4E65656450726F636573734E616D6509095072
+      65636973696F6E02000453697A6502000001044E616D650604436F6465094669
+      656C644E616D650604436F64650844617461547970650218084461746153697A
+      6502320549734B6579080F4E65656450726F636573734E616D65090950726563
+      6973696F6E02000453697A6502000001044E616D650606425F436F6465094669
+      656C644E616D650606425F436F64650844617461547970650218084461746153
+      697A6502320549734B6579080F4E65656450726F636573734E616D6509095072
+      65636973696F6E02000453697A6502000001044E616D6506044E616D65094669
+      656C644E616D6506044E616D650844617461547970650218084461746153697A
+      6503C8000549734B6579080F4E65656450726F636573734E616D650909507265
+      636973696F6E02000453697A6502000001044E616D650605556E697473094669
+      656C644E616D650605556E697473084461746154797065021808446174615369
+      7A6502140549734B6579080F4E65656450726F636573734E616D650909507265
+      636973696F6E02000453697A6502000001044E616D650609497353756D426173
+      65094669656C644E616D650609497353756D4261736508446174615479706502
+      05084461746153697A6502010549734B6579080F4E65656450726F636573734E
+      616D650909507265636973696F6E02000453697A6502000001044E616D650606
+      49734C656166094669656C644E616D65060649734C6561660844617461547970
+      650205084461746153697A6502010549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      060C4465616C5175616E74697479094669656C644E616D65060C4465616C5175
+      616E746974790844617461547970650206084461746153697A6502080549734B
+      6579080F4E65656450726F636573734E616D650909507265636973696F6E0200
+      0453697A6502000001044E616D65060E4465616C546F74616C50726963650946
+      69656C644E616D65060E4465616C546F74616C50726963650844617461547970
+      650206084461746153697A6502080549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      060A51635175616E74697479094669656C644E616D65060A51635175616E7469
+      74790844617461547970650206084461746153697A6502080549734B6579080F
+      4E65656450726F636573734E616D650909507265636973696F6E02000453697A
+      6502000001044E616D65060C5163546F74616C5072696365094669656C644E61
+      6D65060C5163546F74616C507269636508446174615479706502060844617461
+      53697A6502080549734B6579080F4E65656450726F636573734E616D65090950
+      7265636973696F6E02000453697A6502000001044E616D650609516342474C43
+      6F6465094669656C644E616D650609516342474C436F64650844617461547970
+      650218084461746153697A6503FF000549734B6579080F4E65656450726F6365
+      73734E616D650909507265636973696F6E02000453697A6502000001044E616D
+      650608516342474C4E756D094669656C644E616D650608516342474C4E756D08
+      44617461547970650218084461746153697A6503FF000549734B6579080F4E65
+      656450726F636573734E616D650909507265636973696F6E02000453697A6502
+      000000}
+  end
+end

+ 36 - 0
SubTenderGather/stgSubGatherFileDm.pas

@@ -0,0 +1,36 @@
+unit stgSubGatherFileDm;
+// 导入导出汇总结果,连接数据表
+
+interface
+
+uses
+  SysUtils, Classes, sdDB, sdProvider, ADODB, DB;
+
+type
+  TstgSubGatherData = class(TDataModule)
+    sdpBills: TsdADOProvider;
+    sddBills: TsdDataSet;
+  private
+  public
+    procedure Open(AConnection: TADOConnection);
+    procedure Save;
+  end;
+
+implementation
+
+{$R *.dfm}
+
+{ TstgSubGatherData }
+
+procedure TstgSubGatherData.Open(AConnection: TADOConnection);
+begin
+  sdpBills.Connection := AConnection;
+  sddBills.Open;
+end;
+
+procedure TstgSubGatherData.Save;
+begin
+  sddBills.Save;
+end;
+
+end.

+ 30 - 0
SubTenderGather/stgTables.pas

@@ -0,0 +1,30 @@
+unit stgTables;
+
+interface
+
+uses
+  DataBaseTables;
+
+const
+  sStgBills = 'Bills';
+  tdStgBills : array [0..14] of TScFieldDef = (
+    (FieldName: 'ID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: True; ForceUpdate: False),
+    (FieldName: 'ParentID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'NextSiblingID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Code'; FieldType: ftString; Size: 50; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'B_Code'; FieldType: ftString; Size: 50; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Name'; FieldType: ftString; Size: 200; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Units'; FieldType: ftString; Size: 50; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'IsSumBase'; FieldType: ftBoolean; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'IsLeaf'; FieldType: ftBoolean; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'DealQuantity'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'DealTotalPrice'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'QcQuantity'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'QcTotalPrice'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'QcBGLCode'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'QcBGLNum'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False)
+  );
+
+implementation
+
+end.

+ 2 - 2
Units/CacheTree.pas

@@ -55,7 +55,7 @@ type
 
 
     function GetNodeID(ANode: TCacheNode): Integer;
     function GetNodeID(ANode: TCacheNode): Integer;
   public
   public
-    constructor Create(ACacheTree: TCacheTree; AID: Integer);
+    constructor Create(ACacheTree: TCacheTree; AID: Integer); virtual;
     destructor Destroy; override;
     destructor Destroy; override;
 
 
     procedure InsertChild(AChildNode: TCacheNode);
     procedure InsertChild(AChildNode: TCacheNode);
@@ -87,7 +87,7 @@ type
     function GetFirstNode: TCacheNode;
     function GetFirstNode: TCacheNode;
     procedure SetNewNodeID(const Value: Integer);
     procedure SetNewNodeID(const Value: Integer);
   protected
   protected
-    function GetNewNodeID: Integer;   
+    function GetNewNodeID: Integer;
     function GetNewNode: TCacheNode; virtual;
     function GetNewNode: TCacheNode; virtual;
   public
   public
     constructor Create; virtual;
     constructor Create; virtual;

+ 1 - 1
Units/GclBillsGatherModel.pas

@@ -1077,7 +1077,7 @@ constructor TLeafXmjNode.Create(ALeafXmj, APeg: TBillsIDTreeNode);
   begin
   begin
     // 如果计量单元节点的名称为桩号(转化为判断计量单元节点与桩号节点为同一个)
     // 如果计量单元节点的名称为桩号(转化为判断计量单元节点与桩号节点为同一个)
     if not Assigned(APegNode) or (ANode.ID = APegNode.ID) then
     if not Assigned(APegNode) or (ANode.ID = APegNode.ID) then
-      // 取分工程
+      // 取分工程
       Result := GetNameFenXiang(ANode, APegNode)
       Result := GetNameFenXiang(ANode, APegNode)
     // 反之,取分项工程+计量单元
     // 反之,取分项工程+计量单元
     else
     else

+ 48 - 1
Units/ProjectData.pas

@@ -143,7 +143,15 @@ type
     {OpenForGather: BillsData, BillsMeasureTree, DealPaymentData, BGLData, PhaseData(根据PhaseIndex指定打开)}
     {OpenForGather: BillsData, BillsMeasureTree, DealPaymentData, BGLData, PhaseData(根据PhaseIndex指定打开)}
     procedure OpenForGather(const AFileName: string; APhaseIndex: Integer = -1);
     procedure OpenForGather(const AFileName: string; APhaseIndex: Integer = -1);
     {OpenForSignOnline: BillsData, BillsMeasureTree, PhaseData(根据PhaseIndex指定打开)}
     {OpenForSignOnline: BillsData, BillsMeasureTree, PhaseData(根据PhaseIndex指定打开)}
+<<<<<<< HEAD
     procedure OpenForSignOnline(AProjRec: TsdDataRecord; APhaseIndex: Integer = -1);
     procedure OpenForSignOnline(AProjRec: TsdDataRecord; APhaseIndex: Integer = -1);
+=======
+    procedure OpenForSignOnline(const AFileName: string; APhaseIndex: Integer = -1);
+    {OpenForSumUpBase: BillsData, BillsComplieTree}
+    procedure OpenForSumUpBase(const AFileName: string);
+    {OpenForSumUpGather: BillsData, BillsMeasureTree, PhaseData(根据PhaseIndex指定打开),直接调用OpenForSignOnline}
+    procedure OpenForSumUpGather(const AFileName: string; APhaseIndex: Integer = -1);
+>>>>>>> sumUp
     //-----------------------  End ---后台打开 ------------------------
     //-----------------------  End ---后台打开 ------------------------
 
 
     procedure SaveDebugFile(const AFileName: string);
     procedure SaveDebugFile(const AFileName: string);
@@ -196,6 +204,7 @@ type
 
 
     procedure ImportCloudTenderFile(const AFileName: string);
     procedure ImportCloudTenderFile(const AFileName: string);
     procedure ImportDmfFile(const AFileName: string);
     procedure ImportDmfFile(const AFileName: string);
+    procedure ImportSubTenderGather(const AFileName: string);
 
 
     function CheckPassword: Boolean;
     function CheckPassword: Boolean;
 
 
@@ -268,7 +277,11 @@ implementation
 uses UtilMethods, Globals, ProjectCommands, sdIDTree, StageDm,
 uses UtilMethods, Globals, ProjectCommands, sdIDTree, StageDm,
   ZJJLDm, PHPWebDm, XMLDoc, XMLIntf, ConstUnit, PasswordInputFrm,
   ZJJLDm, PHPWebDm, XMLDoc, XMLIntf, ConstUnit, PasswordInputFrm,
   mProgressProFrm, mDataRecord, ConditionalDefines, DbTreeImport,
   mProgressProFrm, mDataRecord, ConditionalDefines, DbTreeImport,
+<<<<<<< HEAD
   StrUtils, sdProvider, CalcDecimal, Math, CslJson, OrderCheckerFme;
   StrUtils, sdProvider, CalcDecimal, Math, CslJson, OrderCheckerFme;
+=======
+  StrUtils, sdProvider, CalcDecimal, Math, stgSubGatherFile;
+>>>>>>> sumUp
 
 
 { TProjectData }
 { TProjectData }
 
 
@@ -1462,7 +1475,7 @@ begin
   FBillsData.Open(FConnection.Connection);
   FBillsData.Open(FConnection.Connection);
   FBillsCompileData.Open;
   FBillsCompileData.Open;
   FDealPaymentData.Open(FConnection.Connection);
   FDealPaymentData.Open(FConnection.Connection);
-  FBGLData.Open(FConnection.Connection);  
+  FBGLData.Open(FConnection.Connection);
 end;
 end;
 
 
 procedure TProjectData.OpenForReply(const AFileName: string);
 procedure TProjectData.OpenForReply(const AFileName: string);
@@ -2189,6 +2202,7 @@ begin
   FIsGuest := Value;
   FIsGuest := Value;
 end;
 end;
 
 
+<<<<<<< HEAD
 procedure TProjectData.LoadCheckersData;
 procedure TProjectData.LoadCheckersData;
 var
 var
   sURL: string;
   sURL: string;
@@ -2208,6 +2222,39 @@ begin
         Checkers.LastChecker := Checkers.Item[iIndex];
         Checkers.LastChecker := Checkers.Item[iIndex];
     end;
     end;
   end
   end
+=======
+procedure TProjectData.OpenForSumUpBase(const AFileName: string);
+begin
+  FProjectID := -1;
+  UnZipFile(AFileName, TempPath);
+  FConnection.Open(MainFileName);
+  UpdateProjectDataBase;
+  FProjProperties.Open(FConnection.Connection);
+  UpdateOldData;
+  FBillsData.Open(FConnection.Connection);
+  FBillsCompileData.Open;
+end;
+
+procedure TProjectData.OpenForSumUpGather(const AFileName: string;
+  APhaseIndex: Integer);
+begin
+  OpenForSignOnline(AFileName, APhaseIndex);
+end;
+
+procedure TProjectData.ImportSubTenderGather(const AFileName: string);
+var
+  vImportor: TstgSubGatherFileImportor;
+begin
+  if PhaseData.StageDataReadOnly then Exit;
+
+  vImportor := TstgSubGatherFileImportor.Create;
+  try
+    vImportor.ImportGatherDataTo(PhaseData.StageData, AFileName);
+  finally
+    CalculateAll;
+    vImportor.Free;
+  end;
+>>>>>>> sumUp
 end;
 end;
 
 
 end.
 end.