# DYNAMIC - COL - ROW BC FIX

## Ý NGHĨA CHỨC NĂNG

* Báo cáo fix. Tạo dynamic dòng và cột
* Nhóm cột&#x20;
* dòng tổng cộng có điều kiện dạng where thay vì theo id&#x20;

  <figure><img src="https://3934179848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpqWC051kMhpZgqZaU9Oy%2Fuploads%2FOKjIgrUAlWp1alap7A5v%2FbaocaoDynamic.png?alt=media&#x26;token=9c901923-e5d5-4982-8066-844b95e1ae4b" alt=""><figcaption><p>Mẫu báo cáo</p></figcaption></figure>

  <figure><img src="https://3934179848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpqWC051kMhpZgqZaU9Oy%2Fuploads%2FcBrEIEil35ibavbkXeYF%2FbaocaoDynamic-congthuc-fix.png?alt=media&#x26;token=e9c85b91-a37d-4032-89d7-8d9ff909765b" alt=""><figcaption><p>Công thức báo cáo</p></figcaption></figure>

## NGUYÊN TẮC CHUNG

* Báo cáo tích vào:&#x20;
  * Fix
  * Dynamic column
* code trước tất cả
  * Tính toán ra dynamicRow
  * Tính toán ra dynamicCol
* code Hậu xử lý
  * Viết các hàm tính toán của dòng chi tiết
    * Ví dụ psNoKhoanmuc(idKhoanmuc, thang)
  * Viết các hàm tính toán của dòng tổng
    * Ví dụ psNoKhoanmuc\_sum(dieukienWhereKhoanmuc, thang)
* Nếu có nhiều dynamicRow thì số lượng tham số thay đổi theo cột nên đồng bộ với nhau giữa các hàm. Ví dụ,&#x20;
  * psNoKhoanmuc(tkno,tkco,-khoanmuc,-bophan,-thang)
  * psNoDoanhthu(tkno,tkco,-khoanmuc,-bophan,-thang)

## TRƯỚC TẤT CẢ

* Hàm chính:
  * Tạo báo cáo phụ, phục vụ tính toán cho các hàm dynamicRow và dynamicCol phía dưới
* Viết các hàm dynamicRow
  * Sinh ra các dòng tự động: Cột chỉ tiêu và cột công thức
  * Cột công thức, thì thay đổi tham số tương ứng với việc chèn dòng. Ví dụ, chèn dòng theo khoanmuc, thì công thức sẽ thay đổi theo tham số khoanmuc
* Viết hàm dynamicCol
  * Sinh ra các cột tự động
  * Nhân bản công thức cột đầu tiên. Sau đó, thay đổi tham số cho cột vừa nhân bản. Ví dụ, chèn cột theo tháng, bộ phận thì công thức cần thay đổi tham số tháng, bộ phận
  * Xử lý nhóm cột nếu có
* Code của bài toán trên như sau:&#x20;

```csharp
public DateTime TuNgay, DenNgay;
	public DataTable dtBaocaoPhu;
	#region phục vụ tính nhóm cột bscpar
	// liệt kê các nhóm cột theo cú pháp 'Tên nhóm cột([Tên cột bắt đầu],[Tên cột kết thúc])0#'
	public DataRow drReport0;
	public string tencot = "";
	public dynamic f25;
	#endregion phục vụ tính nhóm cột bscpar
	public DataTable DMain(DataTable dtColumns, DataRow drReport, FOR0025 formBaoCao)
	{
		// //Viết code dưới dòng này(chỉnh sửa cấu trúc hiển thị báo cáo)
		#region phục vụ tính nhóm cột bscpar
		drReport0 = drReport;
		f25 = formBaoCao;
		#endregion phục vụ tính nhóm cột bscpar
		#region trường hợp chạy báo cáo FIX dưới local thì thực hiện chạy báo cáo con rùi add vào dữ liệu báo cáo sau đó tính toán dựa vào bảng đó

		DateTime daunam = new DateTime();
		DateTime tungay = formBaoCao.TuNgay;
		if(Convert.ToInt16(_Vari.DrCus["thangtaichinh"]) - tungay.Month <= 0)
		{
			daunam = new DateTime(tungay.Year, Convert.ToInt16(_Vari.DrCus["thangtaichinh"]), 01);
		}
		else
		{
			daunam = new DateTime(tungay.Year - 1, Convert.ToInt16(_Vari.DrCus["thangtaichinh"]), 01);
		}

		#endregion: Tính thời gian đầu năm
		TuNgay = formBaoCao.TuNgay;
		DenNgay = formBaoCao.DenNgay;
		string where = formBaoCao.GetWhereCondition(false);//.Replace("where", "").Replace("WHERE", "");
		dtBaocaoPhu = formBaoCao.ChayBaoCao(0, "BCP_KQKD_HPLUX", "Daubc=0", where, formBaoCao.TuNgay , formBaoCao.DenNgay);
		formBaoCao.AddTable("BaoCaoPhu", dtBaocaoPhu);

		return dtColumns;
	}

	// -1, -2, -3 -4: loại doanh thu -1, khoản mục-2, bộ phận-3, tháng -4
	public string dynamicRow_LoaiDoanhThu(string strTen)
	{
		/*
		- hàm có nhiệm vụ sinh các dòng tự động
		- các dòng sinh tự động, bằng cách chèn dòng vào dtDynamicReportColumn[ten,giatri]
		- dtDynamicReportColumn[ten,giatri]: tên là nội dung hiển thị của cột chỉ tiêu (cột chứa tên hàm này dynamicRow_LoaiDoanhThu)
			- giatri là tên hàm được viết ở code Hauxuly. và thay đổi tham số tương ứng với tham số sinh dòng tự động
			- ví dụ, hàm có tên là psCoLoaiDoanhThu(tkno,tkco,loaiDoanthu,khoanmuc,bophan,thang)
			- trong đó, việc sinh dòng tự động đang xét theo yếu tố khoanmuc, nên hàm trên sẽ được thay đổi theo từng dòng ở tham số khoanmuc
				-  psCoLoaiDoanhThu(tkno,tkco,loaiDoanthu,@khoanmuc,bophan,thang)
		*/
		// tính toán lần đầu tiên bảng cần par
		if(_Vari.FormChinh.dtDynamicReportColumn.Rows.Count<= 0)
		{
			DataView dvBaocaophu = new DataView(dtBaocaoPhu);
			dvBaocaophu.RowFilter = "tkno like '51%' or tkno like '711%'";
			DataTable dtBaocaophu0 = dvBaocaophu.ToTable(true, new string[] { "loaidoanhthu", "loaidoanhthuMa", "loaidoanhthuTen" });

			DataRow dr;
			//// nếu dvBaocaophu không có dòng nào thì sao.
			for (int i = 0; i < dtBaocaophu0.Rows.Count; i++)
			{
				dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
				dr["ten"] = new string(' ', 5) +" - " +dtBaocaophu0.Rows[i]["loaidoanhthuTen"].ToString();
				// điền công thức cho cột tổng đầu tiên.// 
				dr["giatri"] = "psCoLoaiDoanhThu(511_515_711,911,"+ dtBaocaophu0.Rows[i]["loaidoanhthu"]+",-2,-3,-4)";

				// psNoKhoanmuc(staikhoan-"632_641_642", tkDoiung-"911", loaidoanhthu - 1,khoanmuc-2, bophan-3, thang-4);
				_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
			}
		}

		return strTen;
	}

	// -1, -2, -3 -4: loại doanh thu -1, khoản mục-2, bộ phận-3, tháng -4
	public string dynamicRow_GiaVon(string strTen)
	{
		// tính toán lần đầu tiên bảng cần par
		if(_Vari.FormChinh.dtDynamicReportColumn.Rows.Count<= 0)
		{
			DataView dvBaocaophu = new DataView(dtBaocaoPhu);
			dvBaocaophu.RowFilter = "tkno like '632%'";
			DataTable dtBaocaophu0 = dvBaocaophu.ToTable(true, new string[] { "khoanmuc", "khoanmucMa", "khoanmucTen" });
			DataView dvkhoanmuc = new DataView(_Func.GetTable("KhoanMuc"));

			DataRow dr;
			//// nếu dvBaocaophu không có dòng nào thì sao.
			for (int i = 0; i < dtBaocaophu0.Rows.Count; i++)
			{
				dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
				dr["ten"] = new string(' ', 5) +" - " +dtBaocaophu0.Rows[i]["khoanmucTen"].ToString();
				// điền công thức cho cột tổng đầu tiên.// 
				dr["giatri"] = "psNoKhoanmuc(632,911,-1,"+ dtBaocaophu0.Rows[i]["khoanmuc"]+",-3,-4)";

				// psNoKhoanmuc(staikhoan-"632_641_642", tkDoiung-"911", loaidoanhthu - 1,khoanmuc-2, bophan-3, thang-4);
				_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
			}
		}

		return strTen;
	}

	// -1, -2, -3 -4: loại doanh thu -1, khoản mục-2, bộ phận-3, tháng -4
	public string dynamicRow_NhanCong(string strTen)
	{
		// tính toán lần đầu tiên bảng cần par
		if(_Vari.FormChinh.dtDynamicReportColumn.Rows.Count<= 0)
		{
			DataView dvBaocaophu = new DataView(dtBaocaoPhu);
			dvBaocaophu.RowFilter = "(tkno like '64%' or tkno like '81%') and khoanmucMa like '02.01%'";
			DataTable dtBaocaophu0 = dvBaocaophu.ToTable(true, new string[] { "khoanmuc", "khoanmucMa", "khoanmucTen" });
			DataView dvkhoanmuc = new DataView(_Func.GetTable("KhoanMuc"));

			DataRow dr;
			//// nếu dvBaocaophu không có dòng nào thì sao.
			for (int i = 0; i < dtBaocaophu0.Rows.Count; i++)
			{
				dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
				dr["ten"] = new string(' ', 5) +" - " +dtBaocaophu0.Rows[i]["khoanmucTen"].ToString();
				// điền công thức cho cột tổng đầu tiên.// 
				dr["giatri"] = "psNoKhoanmuc(64_81,911,-1,"+ dtBaocaophu0.Rows[i]["khoanmuc"]+",-3,-4)";

				// psNoKhoanmuc(staikhoan-"632_641_642", tkDoiung-"911", loaidoanhthu - 1,khoanmuc-2, bophan-3, thang-4);
				_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
			}
		}

		return strTen;
	}

	// -1, -2, -3 -4: loại doanh thu -1, khoản mục-2, bộ phận-3, tháng -4
	public string dynamicRow_HoaHong(string strTen)
	{
		// tính toán lần đầu tiên bảng cần par
		if(_Vari.FormChinh.dtDynamicReportColumn.Rows.Count<= 0)
		{
			DataView dvBaocaophu = new DataView(dtBaocaoPhu);
			dvBaocaophu.RowFilter = "(tkno like '64%' or tkno like '81%') and khoanmucMa like '02.02%'";
			DataTable dtBaocaophu0 = dvBaocaophu.ToTable(true, new string[] { "khoanmuc", "khoanmucMa", "khoanmucTen" });
			DataView dvkhoanmuc = new DataView(_Func.GetTable("KhoanMuc"));

			DataRow dr;
			//// nếu dvBaocaophu không có dòng nào thì sao.
			for (int i = 0; i < dtBaocaophu0.Rows.Count; i++)
			{
				dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
				dr["ten"] = new string(' ', 5) +" - " +dtBaocaophu0.Rows[i]["khoanmucTen"].ToString();
				// điền công thức cho cột tổng đầu tiên.// 
				dr["giatri"] = "psNoKhoanmuc(64_81,911,-1,"+ dtBaocaophu0.Rows[i]["khoanmuc"]+",-3,-4)";

				// psNoKhoanmuc(staikhoan-"632_641_642", tkDoiung-"911", loaidoanhthu - 1,khoanmuc-2, bophan-3, thang-4);
				_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
			}
		}

		return strTen;
	}

	// -1, -2, -3 -4: loại doanh thu -1, khoản mục-2, bộ phận-3, tháng -4
	public string dynamicRow_MatBang(string strTen)
	{
		// tính toán lần đầu tiên bảng cần par
		if(_Vari.FormChinh.dtDynamicReportColumn.Rows.Count<= 0)
		{
			DataView dvBaocaophu = new DataView(dtBaocaoPhu);
			dvBaocaophu.RowFilter = "(tkno like '64%' or tkno like '81%') and khoanmucMa like '02.03%'";
			DataTable dtBaocaophu0 = dvBaocaophu.ToTable(true, new string[] { "khoanmuc", "khoanmucMa", "khoanmucTen" });
			DataView dvkhoanmuc = new DataView(_Func.GetTable("KhoanMuc"));

			DataRow dr;
			//// nếu dvBaocaophu không có dòng nào thì sao.
			for (int i = 0; i < dtBaocaophu0.Rows.Count; i++)
			{
				dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
				dr["ten"] = new string(' ', 5) +" - " +dtBaocaophu0.Rows[i]["khoanmucTen"].ToString();
				// điền công thức cho cột tổng đầu tiên.// 
				dr["giatri"] = "psNoKhoanmuc(64_81,911,-1,"+ dtBaocaophu0.Rows[i]["khoanmuc"]+",-3,-4)";

				// psNoKhoanmuc(staikhoan-"632_641_642", tkDoiung-"911", loaidoanhthu - 1,khoanmuc-2, bophan-3, thang-4);
				_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
			}
		}

		return strTen;
	}

	// -1, -2, -3 -4: loại doanh thu -1, khoản mục-2, bộ phận-3, tháng -4
	public string dynamicRow_Khac(string strTen)
	{
		// tính toán lần đầu tiên bảng cần par
		if(_Vari.FormChinh.dtDynamicReportColumn.Rows.Count<= 0)
		{
			DataView dvBaocaophu = new DataView(dtBaocaoPhu);
			dvBaocaophu.RowFilter = "(tkno like '64%' or tkno like '81%') and khoanmucMa like '02.04%'";
			DataTable dtBaocaophu0 = dvBaocaophu.ToTable(true, new string[] { "khoanmuc", "khoanmucMa", "khoanmucTen" });
			DataView dvkhoanmuc = new DataView(_Func.GetTable("KhoanMuc"));

			DataRow dr;
			//// nếu dvBaocaophu không có dòng nào thì sao.
			if(dtBaocaophu0.Rows.Count != 0)
			{
				for (int i = 0; i < dtBaocaophu0.Rows.Count; i++)
				{
					dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
					dr["ten"] = new string(' ', 5) +" - " +dtBaocaophu0.Rows[i]["khoanmucTen"].ToString();
					// điền công thức cho cột tổng đầu tiên.// 
					dr["giatri"] = "psNoKhoanmuc(64_81,911,-1,"+ dtBaocaophu0.Rows[i]["khoanmuc"]+",-3,-4)";

					// psNoKhoanmuc(staikhoan-"632_641_642", tkDoiung-"911", loaidoanhthu - 1,khoanmuc-2, bophan-3, thang-4);
					_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
				}
			}
			else
			{
				dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
				dr["ten"] = new string(' ', 5) +" - Chi phí khác";
				dr["giatri"] = "psNoKhoanmuc(64_81,911,-1,0,-3,-4)";
				// psNoKhoanmuc(staikhoan-"632_641_642", tkDoiung-"911", loaidoanhthu - 1,khoanmuc-2, bophan-3, thang-4);
				_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
			}
		}

		return strTen;
	}

	public string dynamicRowGiaTri(string strGiaTri)
	{
		return strGiaTri;
	}

	public string dynamicCol(string strGT, string ctCotTruoc, string tencottruoc, string tencotnay, DataRow drReportFix)
	{
		// strGT là giá trị cột giá trị của dòng trong dtDynamicReportColumn
		// ctCotTruoc là giá trị công thức cột trước cột đang động cột
		// tencottruoc là columnName cột trước cột tự động
		// tencotnay là cột hiện tại đang tự động tính nhằm replace các biểu thức tính sau cho chính xác tên cột mình cần xử lý
		// drReportFix là dòng dữ liệu trong báo cáo fix trường hợp không lấy cột liền trước có thể gọi các cột liền trước để lấy công thức cần dùng

		/*
		- hàm có nhiệm vụ sinh các cột tự động và nhóm cột
		- cột sinh tự động, bằng cách chèn dòng vào dtDynamicReportColumn[ten,giatri]
		- dtDynamicReportColumn[ten,giatri]: tên là tên cột hiển thị. giatri là điều kiện để xử lý lại công thức của cột vừa nhân bản lên
			- giatri thường có dạng: @kyhieudau_@thamsoThaydoi01_@thamsoThaydoi02
		
		*/
		
		DataView dvBaocaophu = new DataView(dtBaocaoPhu);
		int sothang = (DenNgay.Year*12 + DenNgay.Month)-(TuNgay.Year*12 + TuNgay.Month)+1;
		int iThang = 0;
		DataRow dr;

		if(_Vari.FormChinh.dtDynamicReportColumn.Rows.Count<= 0)
		{
			/*
			- duyệt qua số tháng đề chèn cột tháng.
				- trong 01 tháng
						- duyệt qua tiếp danh mục bộ phận để tạo cột bộ phận của tháng
						- thêm mặc định cột tổng cộng của tháng vào
			- hết duyệt tháng, thì chèn thêm tổng cộng cả năm vào
				- duyệt danh mục bộ phận để tạo cột bộ phận của năm
				- thêm mặc định cột tổng cộng của năm vào
			- nguyên tắc dynamicCol
				- nhân bản công thức cột đầu tiên lên cho cột hiện tại
				- sửa lại công thức của cột hiện tại, thay thế các tham số tương ứng với việc chạy cột.
				- ở ví dụ này, thì việc chạy tương ứng với tháng và bộ phận. nên ta sẽ thay đổi tham số tháng và bộ phận
				- theo quy ước của hàm dynamicRow(tkno,tkco,loaiDoanhthu=-1,khoanmuc =-2,bophan=-3,thang=-4) thì 2 tham số đó tương ứng như sau[thang=-4][bophan=-3]
				- từ đó, ta sẽ ra được đoạn return
					return ctCotTruoc.Replace(tencottruoc, tencotnay)
					.Replace(",-3", strGT.Split('_').Length != 0 ? ","+strGT.Split('_')[2].ToString() : ",-3") // bộ phận 
					.Replace(",-4", strGT.Split('_').Length != 0 ? ","+strGT.Split('_')[1].ToString() : ",-4"); // tháng
				- trong đó;
					strGT là giá trị của bảng dtDynamicReportColumn.col["giatri"]
					col["giatri"] là do ta gán vào dtDynamic theo 1 format quy ước nào đó. ví dụ: Thang_@thang_@bophan; tongThang_@thang_@bophan
					như trên, quy ước là ký hiệu đầu + @thang + @bophan
					sau đó, tại công thức return, ta xử lý thay đổi các tham số -3 và -4 của công thức gốc, bằng strGT (hay là col["giatri"]) ở text:kyhieu_@thang_@bophan
			
			*/
			
			#region:
			DataTable dtBophan = _Func.GetTable("BoPhan");
			DataView dvBP = new DataView(dtBophan);
			dvBP.RowFilter = "BoPhan>0";
			dvBP.Sort = "Ma";
			string tencot = tencotnay;
			for (int i = 0; i < sothang; i++)
			{
				iThang = TuNgay.AddMonths(i).Year*12 + TuNgay.AddMonths(i).Month;
				for(int b = 0; b< dvBP.Count; b++)
				{
					dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
					dr["ten"] = dvBP[b]["ten"].ToString();
					//dr["ten"] = "Tháng_" + TuNgay.AddMonths(i).Month.ToString() + "/" + TuNgay.AddMonths(i).Year.ToString()+" "+ dvBP[b]["Ma"].ToString();
					// //dr["giatri"] = "TH_" + TuNgay.AddMonths(i).Month.ToString() + "_" + TuNgay.AddMonths(i).Year.ToString();// điền giá trị dùng để truyền đầu vào hàm dynamicCol để xử lý
					dr["giatri"] = "thang_" + iThang.ToString()+"_"+dvBP[b]["BoPhan"].ToString();
					_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
				}

				//Thêm cột Tổng cộng của từng tháng
				dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
				dr["ten"] = "Tổng cộng";
				//dr["ten"] = " Tổng tháng_" + TuNgay.AddMonths(i).Month.ToString() + "/" + TuNgay.AddMonths(i).Year.ToString()+" ";
				// //dr["giatri"] = "TH_" + TuNgay.AddMonths(i).Month.ToString() + "_" + TuNgay.AddMonths(i).Year.ToString();// điền giá trị dùng để truyền đầu vào hàm dynamicCol để xử lý
				dr["giatri"] = "tongthang_" + iThang.ToString()+"_-3";
				_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
				#region phục vụ tính nhóm cột bscpar. Tính nhóm cột hiện tại và lưu vết cuột cuối cùng của nhóm hiện tại
				drReport0["NhomCot"] = drReport0["NhomCot"].ToString().Trim()+"Tháng " + TuNgay.AddMonths(i).Month.ToString().Trim()+"("+ tencot + ",".Trim()+ f25.NextNameColumn(tencot, dvBP.Count) +")0#";
				tencot = f25.NextNameColumn(tencot, dvBP.Count+1);
				#endregion
			}

			// tạo cột cho bộ phận, tổng cả năm
			for(int b = 0; b< dvBP.Count; b++)
			{
				dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
				dr["ten"] = dvBP[b]["ten"].ToString();
				dr["giatri"] = "Nam_-1_"+dvBP[b]["BoPhan"].ToString();
				_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);
			}

			// tạo cột cho tổng cả năm
			dr = _Vari.FormChinh.dtDynamicReportColumn.NewRow();
			dr["ten"] = "Tổng cộng";
			dr["giatri"] = "tongNam_-1_-2";
			_Vari.FormChinh.dtDynamicReportColumn.Rows.Add(dr);

			/// tạo nhóm cột theo nguyên tắc: nhomcot = nhomcot + "tổng cộng (" + tencot + "," + f25.NextNameColumn(tencot, @soluongCot) +")0#";
			/// với @soluongCot là số lượng cột ở giữa cột bắt đầu và cột kết thúc của nhóm cột hiện tại
			drReport0["NhomCot"] = drReport0["NhomCot"].ToString().Trim()+"Tổng cộng (" + tencot + ",".Trim()+ f25.NextNameColumn(tencot, 2) +")0#";
			// _Func.TextEditer("Nhomcot: /r"+drReport0["NhomCot"].ToString());
			#endregion
		}

		if(string.IsNullOrWhiteSpace(strGT))
			return ctCotTruoc;
		else
		{
			//return ctCotTruoc;
			return ctCotTruoc.Replace(tencottruoc, tencotnay)
			.Replace(",-3", strGT.Split('_').Length != 0 ? ","+strGT.Split('_')[2].ToString() : ",-3") // bộ phận 
			.Replace(",-4", strGT.Split('_').Length != 0 ? ","+strGT.Split('_')[1].ToString() : ",-4"); // tháng
		}
	}
```

## HẬU XỬ LÝ

* Hàm chính:
  * chạy báo cáo phụ để tạo ra nguồn cho các hàm phía dưới phục vụ tính toán
* Code các hàm phục vụ công thức cột (hoặc gán trong trước tất cả)

```csharp
public DataTable dtbccon;
	public DataTable DMain(DataTable dtDL, string ssele, DataTable dtColumns, DataRow drReport, FOR0025 formBaoCao)
	{
		// if(_Vari.Developer)
		// {
		// MessageBox.Show("dtDL");
		// _Func.ViewTable(dtDL);
		// }
		#region trường hợp chạy báo cáo FIX dưới local thì thực hiện chạy báo cáo con rùi add vào dữ liệu báo cáo sau đó tính toán dựa vào bảng đó
		string where = formBaoCao.GetWhereCondition(false);//.Replace("where", "").Replace("WHERE", "");
		dtbccon = formBaoCao.ChayBaoCao(0, "BCP_KQKD_HPLUX", "Daubc=0", where, formBaoCao.TuNgay , formBaoCao.DenNgay);
		// dtbccon.TableName = "";
		// _Func.ViewTable(dtbccon);
		#endregion

		return dtDL;
	}

	// loaidoanhthu-1, khoanmuc-2,bophan-3,thang-4
	public object psCoLoaiDoanhThu(string dkTaikhoan, string tkDoiung, int loaidoanhthu, int khoanmuc, int bophan, int thang)
	{
		/*
		- dkTaikhoan: là truyền 1 danh sách tài khoản, phân tách bằng dấu _ ; Ví dụ; 511_515_711
			- câu lệnh where tài khoản: sTkno.ToString().Contains("_"+ r.Field<string>("TKNO").Trim() +"_")
		- loaidoanhthu,khoanmuc, bophan, thang: nếu muốn loại trừ khi tính toán thì điền số âm. 
			- mặc định tuần tự là: -1,-2,-3,-4
			- quan trọng: vì phải xử lý nhân bản cột lên. nên thứ tự phải đúng và phải đồng bộ giữa các hàm
			- câu lệnh where idBophan:  && (bophan < 0 || r.Field<int>("bophan").Equals(bophan))
				- nếu tham số bophan < 0 thì coi như thỏa mãn toàn bộ
				- còn không thì (bophan>=0) thì where cột dữ liệu có id thỏa mãn: r.Field<int>("bophan").Equals(bophan)
				
		*/
		decimal result0 = 0, result1 = 0;
		#region: tính ra listTkNo
		List<string> lstTkno = new List<string>();
		lstTkno = dkTaikhoan.Split('_').ToList();
		string sWhereTkno = "";
		for (int i = 0; i < lstTkno.Count; i++)
		{
			sWhereTkno += " ma like '" + lstTkno[i].ToString()+"%'" + (i == (lstTkno.Count-1)?"":" or ");
		}

		string cmm = "select stuff( (select '_'+ ma from dbo.taikhoan WHERE "+ sWhereTkno +" for xml path('')),1,1,'')";
		string sTkno = "_"+_Func.DBEXEC(cmm, true).ToString()+"_";
		#endregion: tính ra listTkNo

		result0 = dtbccon.AsEnumerable().Where(r => (
												sTkno.ToString().Contains("_"+ r.Field<string>("TKNO").Trim() +"_")
												&& r.Field<string>("tkco").StartsWith(tkDoiung.Trim())
												&& (loaidoanhthu<0 || r.Field<int>("loaidoanhthu").Equals(loaidoanhthu)) // && lstKhoanmuc.Contains(r.Field<int>("khoanmuc"))
												&& (bophan < 0 || r.Field<int>("bophan").Equals(bophan))
												&& (thang<0 || r.Field<int>("thang").Equals(thang))
												))
												.Sum(r => r.Field<decimal?>("pscoKynay") ?? 0);
		result1 = dtbccon.AsEnumerable().Where(r => (
												sTkno.ToString().Contains("_"+ r.Field<string>("TKNO").Trim() +"_")
												&& r.Field<string>("tkco").StartsWith(tkDoiung.Trim())
												&& (loaidoanhthu<0 || r.Field<int>("loaidoanhthu").Equals(loaidoanhthu)) //&& lstKhoanmuc.Contains(r.Field<int>("khoanmuc"))
												&& (bophan < 0 || r.Field<int>("bophan").Equals(bophan))
												&& (thang<0 || r.Field<int>("thang").Equals(thang))
												))
												.Sum(r => r.Field<decimal?>("psnoKynay") ?? 0);

		if(result0 == null)result0 = 0;
		if(result1 == null)result1 = 0;
		return result1 - result0; // no - co ; do sau khi ket chuyen thi but toan la 511/911
	}

	public object psNoKhoanmuc(string dkTaikhoan, string tkDoiung, int loaidoanhthu, int khoanmuc, int bophan, int thang)
	{
		decimal result0 = 0, result1 = 0;

		#region: tính ra listTkNo
		List<string> lstTkno = new List<string>();
		lstTkno = dkTaikhoan.Split('_').ToList();
		string sWhereTkno = "";
		for (int i = 0; i < lstTkno.Count; i++)
		{
			sWhereTkno += " ma like '" + lstTkno[i].ToString()+"%'" + (i == (lstTkno.Count-1)?"":" or ");
		}

		string cmm = "select stuff( (select '_'+ ma from dbo.taikhoan WHERE "+ sWhereTkno +" for xml path('')),1,1,'')";
		string sTkno = "_"+_Func.DBEXEC(cmm, true).ToString()+"_";
		#endregion: tính ra listTkNo

		result0 = dtbccon.AsEnumerable().Where(r => (
												sTkno.ToString().Contains("_"+ r.Field<string>("TKNO").Trim() +"_")
												&& r.Field<string>("tkco").StartsWith(tkDoiung.Trim())
												&& (loaidoanhthu<0 || r.Field<int>("loaidoanhthu").Equals(loaidoanhthu))
												&& (khoanmuc<0 || r.Field<int>("khoanmuc").Equals(khoanmuc))
												&& (bophan < 0 || r.Field<int>("bophan").Equals(bophan))
												&& (thang<0 || r.Field<int>("thang").Equals(thang))
												))
												.Sum(r => r.Field<decimal?>("pscoKynay") ?? 0);
		result1 = dtbccon.AsEnumerable().Where(r => (
												sTkno.ToString().Contains("_"+ r.Field<string>("TKNO").Trim() +"_")
												&& r.Field<string>("tkco").StartsWith(tkDoiung.Trim())
												&& (loaidoanhthu<0 || r.Field<int>("loaidoanhthu").Equals(loaidoanhthu))
												&& (khoanmuc<0 || r.Field<int>("khoanmuc").Equals(khoanmuc))
												&& (bophan < 0 || r.Field<int>("bophan").Equals(bophan))
												&& (thang<0 || r.Field<int>("thang").Equals(thang))
												))
												.Sum(r => r.Field<decimal?>("psnoKynay") ?? 0);

		if(result0 == null)result0 = 0;
		if(result1 == null)result1 = 0;
		return result0 - result1; /// lay co - no; do sau khi ket chuyen thi but toan la 911/632
	}

	public object psNoKhoanmuc_where(string dkTaikhoan, string tkDoiung, int loaidoanhthu, string khoanmuc, int bophan, int thang)
	{
		/*
		- dkTaikhoan: là truyền 1 danh sách tài khoản, phân tách bằng dấu _ ; Ví dụ; 511_515_711
			- câu lệnh where tài khoản: sTkno.ToString().Contains("_"+ r.Field<string>("TKNO").Trim() +"_")
		- loaidoanhthu,khoanmuc, bophan, thang: nếu muốn loại trừ khi tính toán thì điền số âm. 
			- mặc định tuần tự là: -1,-2,-3,-4
			- quan trọng: vì phải xử lý nhân bản cột lên. nên thứ tự phải đúng và phải đồng bộ giữa các hàm
			- câu lệnh where idBophan:  && (bophan < 0 || r.Field<int>("bophan").Equals(bophan))
				- nếu tham số bophan < 0 thì coi như thỏa mãn toàn bộ
				- còn không thì (bophan>=0) thì where cột dữ liệu có id thỏa mãn: r.Field<int>("bophan").Equals(bophan)
			- câu lệnh where dk_khoanmuc: && lstKhoanmuc.Contains(r.Field<int>("khoanmuc"))
				- từ dk_khoanmuc, tìm ra list danh sách id_khoanmuc => gán vào lstKhoanmuc
				- sử dụng điều kiện trên để lọc ra các dòng dữ liệu có khoanmuc thuộc listKhoanmuc
		*/
		
		decimal result0 = 0, result1 = 0;

		#region: tính ra listTkNo
		List<string> lstTkno = new List<string>();
		lstTkno = dkTaikhoan.Split('_').ToList();
		string sWhereTkno = "";
		for (int i = 0; i < lstTkno.Count; i++)
		{
			sWhereTkno += " ma like '" + lstTkno[i].ToString()+"%'" + (i == (lstTkno.Count-1)?"":" or ");
		}

		string cmm = "select stuff( (select '_'+ ma from dbo.taikhoan WHERE "+ sWhereTkno +" for xml path('')),1,1,'')";
		string sTkno = "_"+_Func.DBEXEC(cmm, true).ToString()+"_";
		#endregion: tính ra listTkNo

		#region: tính ra lstKhoanmuc
		string cmmKhoanmuc = "select stuff( (select ','+ convert(nvarchar,KhoanMuc) from dbo.KhoanMuc WHERE "+ khoanmuc +" for xml path('')),1,1,'')";
		object sKhoanmuc = _Func.DBEXEC(cmmKhoanmuc, true);
		List<int> lstKhoanmuc = sKhoanmuc.ToString().Split(',').Select(Int32.Parse).ToList();

		#endregion: tính ra lstKhoanmuc

		result0 = dtbccon.AsEnumerable().Where(r => (
												sTkno.ToString().Contains("_"+ r.Field<string>("TKNO").Trim() +"_")
												&& r.Field<string>("tkco").StartsWith(tkDoiung.Trim())
												&& (loaidoanhthu<0 || r.Field<int>("loaidoanhthu").Equals(loaidoanhthu))
												&& lstKhoanmuc.Contains(r.Field<int>("khoanmuc"))
												&& (bophan < 0 || r.Field<int>("bophan").Equals(bophan))
												&& (thang<0 || r.Field<int>("thang").Equals(thang))
												))
												.Sum(r => r.Field<decimal?>("pscoKynay") ?? 0);
		result1 = dtbccon.AsEnumerable().Where(r => (
												sTkno.ToString().Contains("_"+ r.Field<string>("TKNO").Trim() +"_")
												&& r.Field<string>("tkco").StartsWith(tkDoiung.Trim())
												&& (loaidoanhthu<0 || r.Field<int>("loaidoanhthu").Equals(loaidoanhthu))
												&& lstKhoanmuc.Contains(r.Field<int>("khoanmuc"))
												&& (bophan < 0 || r.Field<int>("bophan").Equals(bophan))
												&& (thang<0 || r.Field<int>("thang").Equals(thang))
												))
												.Sum(r => r.Field<decimal?>("psnoKynay") ?? 0);

		if(result0 == null)result0 = 0;
		if(result1 == null)result1 = 0;
		return result0 - result1; /// lay co - no; do sau khi ket chuyen thi but toan la 911/632
	}
```
