daily_sales_exporter.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import mysql.connector
  2. import pandas as pd
  3. from openpyxl import Workbook
  4. from openpyxl.utils.dataframe import dataframe_to_rows
  5. from openpyxl.utils import get_column_letter
  6. class DailySalesExporter:
  7. def __init__(self, db_config):
  8. self.db_config = db_config
  9. self.query = """
  10. SELECT *, IF(temp.`总单数` = 0, 0, temp.`2000+单数` / temp.`总单数`) AS `2000+单数占比`, WEEK(temp.`单据日期`, 1) AS `第几周`
  11. FROM (
  12. SELECT
  13. t1.document_date AS 单据日期,
  14. SUM(CASE WHEN t1.remaining_amount_after_return <= 999 THEN 1 ELSE 0 END) AS `999及以内单数`,
  15. SUM(CASE WHEN t1.remaining_amount_after_return > 999 AND t1.remaining_amount_after_return < 2000 THEN 1 ELSE 0 END) AS `1000-1999单数`,
  16. SUM(CASE WHEN t1.remaining_amount_after_return >= 2000 AND t1.remaining_amount_after_return <= 2899 THEN 1 ELSE 0 END) AS `2000-2899单数`,
  17. SUM(CASE WHEN t1.remaining_amount_after_return > 2899 AND t1.remaining_amount_after_return <= 3999 THEN 1 ELSE 0 END) AS `2900-3999单数`,
  18. SUM(CASE WHEN t1.remaining_amount_after_return > 3999 AND t1.remaining_amount_after_return <= 4999 THEN 1 ELSE 0 END) AS `4000-4999单数`,
  19. SUM(CASE WHEN t1.remaining_amount_after_return > 4999 AND t1.remaining_amount_after_return <= 7999 THEN 1 ELSE 0 END) AS `5000-7999单数`,
  20. SUM(CASE WHEN t1.remaining_amount_after_return > 7999 THEN 1 ELSE 0 END) AS `8000以上单数`,
  21. SUM(CASE WHEN t2.refund_meets_big_order != '不符合' THEN 1 ELSE 0 END) AS `满足奖励条件大单数`,
  22. MAX(t2.big_order_items) AS `最大单件数`,
  23. MAX(t2.big_order_amount) AS `最大单金额`,
  24. COUNT(1) AS `总单数`,
  25. SUM(CASE WHEN t1.remaining_amount_after_return >= 2000 THEN 1 ELSE 0 END) AS `2000+单数`
  26. FROM sd_sales_order AS t1
  27. LEFT JOIN sd_big_sales_order AS t2 ON t1.sale_id = t2.sale_id
  28. GROUP BY t1.document_date
  29. ) AS temp;
  30. """
  31. def export(self, output_file='output_with_weekly_summary.xlsx'):
  32. global cursor, connection
  33. try:
  34. connection = mysql.connector.connect(**self.db_config)
  35. cursor = connection.cursor()
  36. cursor.execute(self.query)
  37. rows = cursor.fetchall()
  38. columns = [desc[0] for desc in cursor.description]
  39. finally:
  40. cursor.close()
  41. connection.close()
  42. df = pd.DataFrame(rows, columns=columns)
  43. df['单据日期'] = pd.to_datetime(df['单据日期'])
  44. df = df.sort_values('单据日期').reset_index(drop=True)
  45. weekly_summary = df.groupby('第几周').agg({
  46. col: 'sum' for col in df.columns if col not in ['单据日期', '2000+单数占比', '第几周']
  47. }).reset_index()
  48. weekly_summary['2000+单数'] = pd.to_numeric(weekly_summary['2000+单数'], errors='coerce')
  49. weekly_summary['总单数'] = pd.to_numeric(weekly_summary['总单数'], errors='coerce')
  50. weekly_summary['2000+单数占比'] = (weekly_summary['2000+单数'] / weekly_summary['总单数']).fillna(0).round(4)
  51. new_data = []
  52. current_week = None
  53. for _, row in df.iterrows():
  54. week_group = row['第几周']
  55. if current_week != week_group and current_week is not None:
  56. summary_row = weekly_summary[weekly_summary['第几周'] == current_week].iloc[0].to_dict()
  57. start_date = df[df['第几周'] == current_week]['单据日期'].min().strftime('%m-%d')
  58. end_date = df[df['第几周'] == current_week]['单据日期'].max().strftime('%m-%d')
  59. summary_row['单据日期'] = f"{start_date}-{end_date} 汇总"
  60. new_data.append(summary_row)
  61. new_data.append(row.to_dict())
  62. current_week = week_group
  63. if current_week is not None:
  64. summary_row = weekly_summary[weekly_summary['第几周'] == current_week].iloc[0].to_dict()
  65. start_date = df[df['第几周'] == current_week]['单据日期'].min().strftime('%m-%d')
  66. end_date = df[df['第几周'] == current_week]['单据日期'].max().strftime('%m-%d')
  67. summary_row['单据日期'] = f"{start_date}-{end_date} 汇总"
  68. new_data.append(summary_row)
  69. new_df = pd.DataFrame(new_data).drop(columns=['第几周'])
  70. wb = Workbook()
  71. ws = wb.active
  72. for r in dataframe_to_rows(new_df, index=False, header=True):
  73. ws.append(r)
  74. header = {cell.value: cell.column for cell in ws[1]}
  75. numeric_columns = [
  76. '999及以内单数', '1000-1999单数', '2000-2899单数', '2900-3999单数',
  77. '4000-4999单数', '5000-7999单数', '8000以上单数', '满足奖励条件大单数',
  78. '最大单件数', '最大单金额', '总单数', '2000+单数'
  79. ]
  80. for col_name in numeric_columns:
  81. if col_name in header:
  82. col_letter = get_column_letter(header[col_name])
  83. for cell in ws[col_letter]:
  84. if cell.row == 1:
  85. continue
  86. cell.number_format = '0'
  87. if '2000+单数占比' in header:
  88. col_letter = get_column_letter(header['2000+单数占比'])
  89. for cell in ws[col_letter]:
  90. if cell.row == 1:
  91. continue
  92. cell.number_format = '0.00%'
  93. wb.save(output_file)
  94. print(f"✅ 数据已成功导出到 {output_file}")
  95. def export_to_dataframe(self):
  96. connection = mysql.connector.connect(**self.db_config)
  97. cursor = connection.cursor()
  98. try:
  99. cursor.execute(self.query)
  100. rows = cursor.fetchall()
  101. columns = [desc[0] for desc in cursor.description]
  102. finally:
  103. cursor.close()
  104. connection.close()
  105. df = pd.DataFrame(rows, columns=columns)
  106. df['单据日期'] = pd.to_datetime(df['单据日期'])
  107. df = df.sort_values('单据日期').reset_index(drop=True)
  108. weekly_summary = df.groupby('第几周').agg({
  109. col: 'sum' for col in df.columns if col not in ['单据日期', '2000+单数占比', '第几周']
  110. }).reset_index()
  111. weekly_summary['2000+单数'] = pd.to_numeric(weekly_summary['2000+单数'], errors='coerce')
  112. weekly_summary['总单数'] = pd.to_numeric(weekly_summary['总单数'], errors='coerce')
  113. weekly_summary['2000+单数占比'] = (weekly_summary['2000+单数'] / weekly_summary['总单数']).fillna(0).round(4)
  114. new_data = []
  115. current_week = None
  116. for _, row in df.iterrows():
  117. week_group = row['第几周']
  118. if current_week != week_group and current_week is not None:
  119. summary_row = weekly_summary[weekly_summary['第几周'] == current_week].iloc[0].to_dict()
  120. start_date = df[df['第几周'] == current_week]['单据日期'].min().strftime('%m-%d')
  121. end_date = df[df['第几周'] == current_week]['单据日期'].max().strftime('%m-%d')
  122. summary_row['单据日期'] = f"{start_date}-{end_date} 汇总"
  123. new_data.append(summary_row)
  124. new_data.append(row.to_dict())
  125. current_week = week_group
  126. if current_week is not None:
  127. summary_row = weekly_summary[weekly_summary['第几周'] == current_week].iloc[0].to_dict()
  128. start_date = df[df['第几周'] == current_week]['单据日期'].min().strftime('%m-%d')
  129. end_date = df[df['第几周'] == current_week]['单据日期'].max().strftime('%m-%d')
  130. summary_row['单据日期'] = f"{start_date}-{end_date} 汇总"
  131. new_data.append(summary_row)
  132. new_df = pd.DataFrame(new_data).drop(columns=['第几周'])
  133. return new_df