5 Commits 4fccec1e4b ... 0713ff73e2

Auteur SHA1 Bericht Datum
  Ping 0713ff73e2 把水电表切换到测试环境 1 jaar geleden
  Ping 9b036b8036 水电费收入报表增加字段备注修改 1 jaar geleden
  Ping a75658d689 综合财务报表:增加续约合同查询,解决月份匹配的bug 1 jaar geleden
  Ping c9eff6d11a 修改退租的审核状态与退款信息 1 jaar geleden
  Ping f4e11683de 退房业务报表中增加费用方向 1 jaar geleden
4 gewijzigde bestanden met toevoegingen van 103 en 49 verwijderingen
  1. 7 11
      退房业务报表.sql
  2. 20 10
      etl_bill_detail.py
  3. 33 28
      etl_utility.py
  4. 43 0
      utils.py

+ 7 - 11
退房业务报表.sql

@@ -10,13 +10,13 @@ select crc.tenant_id, crc.id '合同ID', hhb.dept_id '房源所属门店ID', hou
 	REPLACE(REPLACE(JSON_EXTRACT(crc.`cancel_info`, '$.reason'), '"', ''), 'null', '') '退租备注',
 	REPLACE(REPLACE(JSON_EXTRACT(crc.`cancel_info`, '$.rejectName'), '"', ''), 'null', '') '退租操作人',
 	REPLACE(REPLACE(JSON_EXTRACT(crc.`cancel_info`, '$.rejectTime'), '"', ''), 'null', '') '退租时间',
+	_total.direction '费用方向',
 	_total.kind '费用科目',
-	_total.应收 '应收账单',
-	_total.应付 '应付账单',
-	_total.应付-_total.应收 '应退款金额',
+	_total.original_money '金额',
+	IF(_total.direction='应收', 1, -1) * _total.original_money '应退款金额',
 	_detail.info '财务退款备注',
-	IF(_flow_status.avg_status is null, '', IF(_flow_status.avg_status=1, '待审核', IF(_flow_status.avg_status=3, '审核通过', '部分审核通过'))) '审核状态',
-	IF(_flow_status.avg_status is null, '', IF(_flow_status.avg_status=3, '已退款', IF(_flow_status.avg_status>1, '已部分退款', '未退款'))) '退款信息'
+	IF(_flow_status.avg_status is null, '-', IF(_flow_status.avg_status=1, '待审核', IF(_flow_status.avg_status=3, '审核通过', '部分审核通过'))) '审核状态',
+	IF(_flow_status.avg_status is null, '未处理', IF(_flow_status.avg_status=3, '已退款', IF(_flow_status.avg_status>1, '已部分退款', '未退款'))) '退款信息'
 from yuxin_contract.cont_renter_contract crc 
 left join yuxin_house.hse_house_base hhb on hhb.is_delete=0 and hhb.id=crc.house_id
 left join yuxin_setting.setting_department house_sd on house_sd.id=hhb.dept_id and house_sd.is_delete=0
@@ -26,15 +26,11 @@ left join yuxin_setting.setting_department maintainer_sd on maintainer_sd.id=mai
 left join yuxin_setting.setting_employee_info mt_emp on mt_emp.id=crc.maintainer_id and mt_emp.is_delete=0
 left join yuxin_contract.cont_renter_info cri on cri.is_delete=0 and cri.customer_type=1 and cri.contract_id=crc.id
 left join (
-    select bd.biz_id, sd.name 'kind',
-    	SUM(IF(bd.fee_direction=1,0,1)*bd.original_money) '应付',
-    	SUM(IF(bd.fee_direction=1,0,1)*bd.occurred_money) '已付',
-    	SUM(IF(bd.fee_direction=1,1,0)*bd.original_money) '应收',
-    	SUM(IF(bd.fee_direction=1,1,0)*bd.occurred_money) '已收'
+    select bd.biz_id, sd.name 'kind', IF(bd.fee_direction=1,'应收','应付') 'direction', SUM(bd.original_money) 'original_money'
     from yuxin_finance.fin_finance_bill_detail bd
 	left join yuxin_setting.setting_dictionary sd on sd.id=bd.fee_subject_id
     where bd.is_valid=1 and bd.is_delete=0 and bd.biz_type=2
-    group by bd.biz_id,sd.name
+    group by bd.biz_id,sd.name,bd.fee_direction
 ) _total on _total.biz_id= crc.id
 left join (
 	select bd.biz_id, GROUP_CONCAT(CONCAT(sd.name, bd.original_money)) 'info'

+ 20 - 10
etl_bill_detail.py

@@ -12,11 +12,12 @@ import json
 from dateutil.relativedelta import relativedelta
 import calendar
 from urllib.parse import quote_plus
-from utils import load_config, truncate_target_db
+from utils import load_config, truncate_target_db, find_renewal_contract
 
 debug = False
 if debug:
-    debug_condition = "and bd.biz_id='1687400201327599617'"  # P.53
+    # debug_condition = "and bd.biz_id='1687400201327599617'"  # P.53
+    debug_condition = "and bd.biz_id='1731870365341253635'"  # 调试押金权责
     # debug_condition = ''
 else:
     debug_condition = ''
@@ -89,11 +90,12 @@ def extract(conn, batch_size, i) -> pd.DataFrame:
             bd.bill_id, bd.id as 'bill_detail_id', bd.fee_subject_id, sd.label as 'fee_subject_label', sd.name as 'fee_subject_name', 
             rc.`type` 'contract_type',
             0 'splitter',
+            rc.quite_date,
             bd.fee_direction, bd.original_money, bd.occurred_money,
             bd.begin_time, bd.end_time, bd.is_occur, rc.cancel_info, bd.predict_time
         from yuxin_finance.fin_finance_bill_detail bd
         left join yuxin_setting.setting_dictionary sd on sd.id=bd.fee_subject_id
-        left join yuxin_contract.cont_renter_contract rc on rc.id=bd.biz_id
+        left join yuxin_contract.cont_renter_contract rc on rc.id=bd.biz_id and rc.is_delete=0
         left join yuxin_house.hse_house_room hhr on hhr.is_delete=0 and hhr.id=rc.house_id
         left join yuxin_house.hse_house_base hhb on hhb.is_delete=0 and hhb.id=rc.house_id
         left join yuxin_setting.setting_department house_sd on house_sd.id=hhb.dept_id and house_sd.is_delete=0
@@ -109,7 +111,7 @@ def extract(conn, batch_size, i) -> pd.DataFrame:
     return source_data
 
 
-def transform(data) -> pd.DataFrame:
+def transform(conn, data) -> pd.DataFrame:
     """ Transforms the dataset into desired structure and filters
         --- 维度:租户,合同,房源,维护人,所属部门,日,财务科目分类,财务科目,应收,应付,实收,实付
         --- 指标:金额(尾差保留在最后一日中)
@@ -131,9 +133,17 @@ def transform(data) -> pd.DataFrame:
 
     # Iterate over each row in the DataFrame
     for index, row in data.iterrows():
-        
+        # 查找续租合同
+        renewed_end_time = find_renewal_contract(conn, row['contract_id'])
+
         begin_date = row['begin_time']
-        end_date = row['end_time']
+        if renewed_end_time is None:
+            end_date = row['quite_date'] if row['quite_date'] is not None and not pd.isnull(
+                row['quite_date']) else row['end_time']
+        else:
+            end_date = renewed_end_time
+
+        # end_date = renewed_end_time
         # Calculate the number of days between the two dates
         num_days = (end_date - begin_date).days + 1
         num_months = (end_date.year - begin_date.year) * 12 + (end_date.month - begin_date.month) + 1
@@ -180,9 +190,9 @@ def transform(data) -> pd.DataFrame:
         while current_month <= end_date:
             first_day = 1
             last_day = calendar.monthrange(current_month.year, current_month.month)[1]
-            if current_month.month == begin_date.month:
+            if current_month.month == begin_date.month and current_month.year == begin_date.year:
                 first_day = begin_date.day
-            if current_month.month == end_date.month:
+            if current_month.month == end_date.month and current_month.year == end_date.year:
                 last_day = end_date.day
             num_days_month = last_day - first_day + 1
             # print('current_month', current_month, first_day, last_day, num_days_month)
@@ -191,7 +201,7 @@ def transform(data) -> pd.DataFrame:
             new_row['day'] = current_month.date()
             new_row['is_apportion'] = 1
             
-            if current_month.month == end_date.month:
+            if current_month.month == end_date.month and current_month.year == end_date.year:
                 # keep remainder in the last day
                 new_row['money'] = remainder
             else:
@@ -315,7 +325,7 @@ def etl():
         # Write the data to the table in batches
         for i in tqdm(range(0, total, batch_size)):
             data = extract(conn, batch_size, i)
-            data = transform(data)
+            data = transform(conn, data)
 
             if debug:
                 print(data.head())

+ 33 - 28
etl_utility.py

@@ -15,7 +15,7 @@ import calendar
 import taosrest as taos
 from taosrest import connect, TaosRestConnection, TaosRestCursor
 from urllib.parse import quote_plus
-from utils import load_config, truncate_target_db
+from utils import load_config, truncate_target_db, update_column_comment
 
 
 debug = False
@@ -27,6 +27,30 @@ if debug:
 else:
     debug_condition = ''
 
+cols = {
+    'tenant_id': [NVARCHAR(10), '租户ID'],
+    'theday': [Date, '日期'],
+    'house_dept_id': [NVARCHAR(32), '房源所属门店ID'],
+    'house_dept_name': [NVARCHAR(32), '房源所属门店名称'],
+    'address': [NVARCHAR(255), '房源地址'],
+    'contract_dept_id': [NVARCHAR(32), '合同所属门店/部门ID'],
+    'contract_dept_name': [NVARCHAR(32), '合同所属门店/部门'],
+    'contract_id': [NVARCHAR(36), '合同ID'],
+    'contract_maintainer': [NVARCHAR(32), '合同维护人'],
+    'renter_name': [NVARCHAR(50), '租客姓名'],
+    'contract_terminate_type': [INTEGER(), '退租类型'],
+    'begin_time': [Date, '合同开始日期'],
+    'end_time': [Date, '合同结束日期'],
+    'quit_time': [Date, '退租日期'],
+    'kind': [NVARCHAR(32), '类型'],
+    'begin_amount': [DECIMAL(10, 2), '期初读数'],
+    'end_amount': [DECIMAL(10, 2), '期末读数'],
+    'amount': [DECIMAL(10, 2), '使用量'],
+    'balance': [DECIMAL(10, 2), '期末余额'],
+    'cost': [DECIMAL(10, 2), '使用金额'],
+    'charge_amount': [DECIMAL(10, 2), '充值总金额'],
+    'clear_amount': [DECIMAL(10, 2), '清零总金额']
+}
 
 
 def query_total(conn) -> int:
@@ -47,7 +71,7 @@ def extract(conn, td_cursor, batch_size, i) -> pd.DataFrame:
         select hhb.dept_id '房源所属门店ID', house_sd.name '房源所属门店名称', hhr.address '房源地址', 
             crc_sd.id '合同所属门店/部门ID', crc_sd.name '合同所属门店/部门',
             crc.id '合同ID', crc_ei.name '合同维护人', cri.name '租客姓名', crc.terminate_type '退租类型', 
-            crc.begin_time, crc.end_time, crc.quite_date, crc.house_id
+            crc.begin_time, crc.end_time, crc.quite_date, crc.house_id, crc.tenant_id
         from yuxin_contract.cont_renter_contract crc 
         left join yuxin_house.hse_house_room hhr on hhr.is_delete=0 and hhr.id=crc.house_id
         left join yuxin_house.hse_house_base hhb on hhb.is_delete=0 and hhb.id=crc.house_id
@@ -214,7 +238,7 @@ def transform(conn, td_cursor, data) -> pd.DataFrame:
     # 费用类型	        显示所选能耗费账单费用类型			    电费、热水费、冷水费、中水费	
 
     # target columns
-    columns = ['theday', 'house_dept_id', 'house_dept_name', 'address', 'contract_dept_id', 'contract_dept_name',
+    columns = ['tenant_id', 'theday', 'house_dept_id', 'house_dept_name', 'address', 'contract_dept_id', 'contract_dept_name',
                'contract_id', 'contract_maintainer', 'renter_name', 'contract_terminate_type',
                'begin_time', 'end_time', 'quit_time', 'kind', 'begin_amount', 'end_amount',
                'amount', 'balance', 'cost', 'charge_amount', 'clear_amount']
@@ -252,6 +276,7 @@ def transform(conn, td_cursor, data) -> pd.DataFrame:
                     continue
 
                 target_data.append({
+                    'tenant_id': row['tenant_id'],
                     'theday': the_time,
                     'house_dept_id': row['房源所属门店ID'],
                     'house_dept_name': row['房源所属门店名称'],
@@ -288,38 +313,16 @@ def load(conn, df: pd.DataFrame, target_db) -> None:
     """
 
     # Define the column types for the table
-    dtype = {
-        'theday': Date,
-        'house_dept_id': NVARCHAR(32),
-        'house_dept_name': NVARCHAR(32),
-        'address': NVARCHAR(255),
-        'contract_dept_id': NVARCHAR(32),
-        'contract_dept_name': NVARCHAR(32),
-        'contract_id': NVARCHAR(36),
-        'contract_maintainer': NVARCHAR(32),
-        'renter_name': NVARCHAR(50),
-        'contract_terminate_type': INTEGER(),
-        'begin_time': Date,
-        'end_time': Date,
-        'quit_time': Date,
-        'kind': NVARCHAR(32),
-        'begin_amount': DECIMAL(10, 2),
-        'end_amount': DECIMAL(10, 2),
-        'amount': DECIMAL(10, 2),
-        'balance': DECIMAL(10, 2),
-        'cost': DECIMAL(10, 2),
-        'charge_amount': DECIMAL(10, 2),
-        'clear_amount': DECIMAL(10, 2)
-    }
+    dtypes = {key: value[0] for key, value in cols.items()}
     # create target table with df.dtypes
     df.to_sql(target_db, con=conn, if_exists='append',
-              index=False, dtype=dtype)
+              index=False, dtype=dtypes)
 
     pass
 
 
 def etl():
-    config = load_config('production')
+    config = load_config()
 
     target_db = 'bi_utility_'
 
@@ -363,6 +366,8 @@ def etl():
             # else:
             load(conn, data, target_db)
 
+        update_column_comment(conn, target_db, cols)
+
     td_conn.close()
     pass
 

+ 43 - 0
utils.py

@@ -1,6 +1,7 @@
 
 import yaml
 from sqlalchemy import text
+from sqlalchemy.types import Date, INTEGER
 
 
 def load_config(env='test'):
@@ -24,3 +25,45 @@ def truncate_target_db(conn, target_db) -> None:
                 TRUNCATE TABLE {target_db}
             """.format(target_db=target_db)
         conn.execute(text(sql))
+
+
+def find_renewal_contract(conn, contract_id):
+    query = """
+        select crc1.id, crc1.begin_time, crc1.end_time, crc1.quite_date, 
+               crc2.id, crc2.begin_time, crc2.end_time, crc2.quite_date, 
+               crc3.id, crc3.begin_time, crc3.end_time, crc3.quite_date
+        from yuxin_contract.cont_renter_contract crc1
+        left join yuxin_contract.cont_renter_contract crc2 on crc2.contract_pid=crc1.id and crc2.is_delete=0 and crc2.contract_status<>4 and crc2.sign_type=2
+        left join yuxin_contract.cont_renter_contract crc3 on crc3.contract_pid=crc2.id and crc3.is_delete=0 and crc3.contract_status<>4 and crc3.sign_type=2
+        where crc1.is_delete=0 and crc1.contract_status<>4 and crc1.sign_type=2
+            and crc1.contract_pid='{contract_id}'
+        """.format(contract_id=contract_id)
+
+    result = conn.execute(text(query)).fetchone()
+    if result is None:
+        return None
+
+    if result[11] is not None:
+        return result[11]
+    elif result[10] is not None:
+        return result[10]
+    elif result[7] is not None:
+        return result[7]
+    elif result[6] is not None:
+        return result[6]
+    elif result[3] is not None:
+        return result[3]
+    elif result[2] is not None:
+        return result[2]
+    return None
+
+
+def update_column_comment(conn, target_db, cols):
+    for key, value in cols.items():
+        dtype = value[0]
+        if dtype == Date:
+            dtype = 'date'
+        elif dtype == INTEGER:
+            dtype = 'INT'
+        conn.execute(text('alter table {target_db} modify column `{col}` {dtype} comment \'{comment}\''
+                          .format(target_db=target_db, col=key, dtype=dtype, comment=value[1])))