Example #1
0
def get_account_nature(df_xsz, name):
    '''
    从本年度序时账获取供应商款项性质
    :param df_xsz: 序时账
    :param name: 供应商名称
    :return: 供应商采购的款项性质
    '''
    df_tmp_xsz = df_xsz[(df_xsz["auxiliary"].str.contains(name, regex=False))
                        & (df_xsz["credit"].abs() > 0)]
    if len(df_tmp_xsz) > 0:
        for obj in gen_df_line(df_tmp_xsz.tail(1)):
            df_supplier_xsz = df_xsz[
                (df_xsz["month"] == obj["month"])
                & (df_xsz["vocher_type"] == obj["vocher_type"]) &
                (df_xsz["vocher_num"] == obj["vocher_num"]) &
                (df_xsz["debit"].abs() > 0)]
            for i in long_term_assets:
                if df_supplier_xsz["tb_subject"].str.contains(i).any():
                    return "长期资产"
            for i in inventory:
                if df_supplier_xsz["tb_subject"].str.contains(i).any():
                    return "材料费"
            for i in expense:
                if df_supplier_xsz["tb_subject"].str.contains(i).any():
                    return "费用"
    return "材料费"
Example #2
0
def add_entry_desc(start_time, end_time, session, df_entry, desc, count,
                   records_length):
    '''
    为凭证所有的分录添加相同的描述
    :param company_name: 公司名
    :param start_time: 开始时间
    :param end_time: 结束时间
    :param session: 数据库session
    :param df_entry: 记账凭证
    :param desc: 描述
    :return: 向数据库添加该凭证的描述
    '''
    for obj in gen_df_line(df_entry):
        add_event(start_time, end_time, session, desc, obj)
    # session.commit()
    # 如果另外的线程调用会引发database is locked错误
    if (count % 500 == 0) or (count == (records_length - 1)):
        session.commit()
Example #3
0
def get_entry_subjects(df_one_entry,subject_name_grade):
    '''
    获取凭证的借贷方科目
    :param df_one_entry: 一笔凭证
    :return: 借方科目列表和贷方科目列表组成的字典{"debit":debit_subjects_list,"credit":credit_subjects_list}
    '''
    debit_subjects = set()
    credit_subjects = set()
    # 获取凭证的借贷方
    for obj in gen_df_line(df_one_entry):
        if abs(obj["debit"]) > 1e-5:
            debit_subjects.add(obj[subject_name_grade])
        else:
            credit_subjects.add((obj[subject_name_grade]))

    debit_subjects_list = list(debit_subjects)
    credit_subjects_list = list(credit_subjects)
    debit_subjects_list.sort()
    credit_subjects_list.sort()

    return {"debit":debit_subjects_list,"credit":credit_subjects_list}
def add_nature(auxiliaries, df_xsz_last, session):
    '''
    为供应商添加属性
    :param auxiliaries: 供应商
    :param df_xsz_last: 凭证
    :param session: 数据库session
    :return:
    '''
    for auxiliary in auxiliaries:
        df_tmp_xsz = df_xsz_last[(
            df_xsz_last["auxiliary"].str.contains(auxiliary.name, regex=False))
                                 & (df_xsz_last["credit"].abs() > 0)]
        if len(df_tmp_xsz) > 0:
            for obj in gen_df_line(df_tmp_xsz.tail(1)):
                df_supplier_xsz = df_xsz_last[
                    (df_xsz_last["month"] == obj["month"])
                    & (df_xsz_last["vocher_type"] == obj["vocher_type"]) &
                    (df_xsz_last["vocher_num"] == obj["vocher_num"]) &
                    (df_xsz_last["debit"].abs() > 0)]
                auxiliary.nature = get_nature(df_supplier_xsz)
            session.commit()
Example #5
0
def handle_one_entry(start_time, end_time, df_xsz, record,
                     not_through_salary_entries, grades, session, count,
                     records_length):
    '''

    :param start_time:
    :param end_time:
    :param df_xsz:
    :param record:
    :param not_through_salary_entries:
    :param grades:
    :param session:
    :param count:
    :param records_length:
    :return:
    '''
    df_tmp = get_df_one_entry(df_xsz, record)
    # 处理没有通过应付职工薪酬核算的职工薪酬
    if len(not_through_salary_entries) > 0:
        res = "{}-{}-{}".format(record["month"], record["vocher_type"],
                                record["vocher_num"])
        if res in not_through_salary_entries:
            for obj in gen_df_line(df_tmp):
                add_event(start_time, end_time, session, "职工薪酬-未通过应付职工薪酬核算",
                          obj)
            session.commit()
        else:
            df_split_entries = split_entry(df_tmp)
            for df_split_entry in df_split_entries:
                handle_entry(df_split_entry, record, grades, start_time,
                             end_time, session, count, records_length)
    else:
        df_split_entries = split_entry(df_tmp)
        for df_split_entry in df_split_entries:
            handle_entry(df_split_entry, record, grades, start_time, end_time,
                         session, count, records_length)
Example #6
0
def check_subject_and_desc_contains(df_one_entry, strs, grades):
    '''
    检查凭证摘要或科目中是否包含特定的字符串
    :param df_one_entry:凭证
    :param strs:字符串或者列表
    :param grades:科目级次
    :return:包含或不包含
    '''
    if not isinstance(strs, list):
        raise Exception("需要传入字符串列表")
    for obj in gen_df_line(df_one_entry):
        containers = []
        desc = obj["description"]
        containers.append(desc)
        for grade in range(grades):
            subject_name = "subject_name_{}".format(grade + 1)
            containers.append(obj[subject_name])
        for container in containers:
            if container == None:
                continue
            for str in strs:
                if str in container:
                    return True
    return False
def get_occours(df_obj_xsz, abs_terminal_value, direction):
    sum = 0.0
    occurs = []
    for item in gen_df_line(df_obj_xsz):
        sum = sum + item.get(direction)
        if sum <= abs_terminal_value:
            occurs.append({
                "occur_time": item["record_time"],
                "value": item.get(direction)
            })
        else:
            occurs.append({
                "occur_time":
                item["record_time"],
                "value":
                abs_terminal_value - (sum - item.get(direction))
            })
            break
    if sum < abs_terminal_value:
        occurs.append({
            "occur_time": 633801600000,
            "value": abs_terminal_value - sum
        })
    return occurs
Example #8
0
def split_entry(df_entry):
    '''
    将一笔凭证拆分成多笔凭证,根据摘要拆分,根据
    :param df_entry:
    :return:
    '''
    # 本年利润凭证不予分拆
    not_split_subjects = ["本年利润"]
    for not_split_subject in not_split_subjects:
        if len(df_entry[df_entry["subject_name_1"] == not_split_subject]) > 0:
            return [df_entry]

    subjects = get_entry_subjects(df_entry, "subject_name_1")
    debit_subjects_list = subjects["debit"]
    credit_subjects_list = subjects["credit"]
    df_entry_debit = df_entry[df_entry["direction"] == "借"]
    df_entry_credit = df_entry[df_entry["direction"] == "贷"]
    #     货币资金支付不同种类的费用进行分拆,收到货币资金,如果对方科目唯一进行分拆
    # 如果一方是货币资金另一方包含两个科目(除去应交税费),则进行分拆,
    #     如果一方是货币资金,另一方是多个科目
    if len(debit_subjects_list) == 1 and (debit_subjects_list[0] in [
            "库存现金", "银行存款"
    ]) and len(credit_subjects_list) > 1:
        res = one_to_many_split(df_entry_debit, df_entry_credit, "debit")
        return res
    elif len(credit_subjects_list) == 1 and (credit_subjects_list[0] in [
            "库存现金", "银行存款"
    ]) and len(debit_subjects_list) > 1:
        res = one_to_many_split(df_entry_credit, df_entry_debit, "credit")
        return res
    # 如果货币资金在多个科目一方
    elif len(debit_subjects_list) == 1 and (debit_subjects_list[0] not in [
            "库存现金", "银行存款"
    ]) and len(credit_subjects_list) > 1 and (
        ("库存现金" in credit_subjects_list) or ("银行存款" in credit_subjects_list)):
        # 如果多个科目中不包含应交税费,则全部分拆,否则仅分拆货币资金
        res = one_to_many_split(df_entry_debit, df_entry_credit, "debit")
        return res
    elif len(credit_subjects_list) == 1 and (credit_subjects_list[0] not in [
            "库存现金", "银行存款"
    ]) and len(debit_subjects_list) > 1 and (("库存现金" in debit_subjects_list) or
                                             ("银行存款" in debit_subjects_list)):
        # 如果多个科目中不包含应交税费,则全部分拆,否则仅分拆货币资金
        res = one_to_many_split(df_entry_debit, df_entry_credit, "debit")
        return res


#     判断摘要是否不止一个,并且借方和贷方同时有多个项目
# 根据相同的摘要进行分类
    df_entry_desctiption = df_entry.drop_duplicates(subset=["description"])
    if len(df_entry_desctiption) > 1 and len(debit_subjects_list) > 1 and len(
            credit_subjects_list) > 1:
        res = []
        for obj in gen_df_line(df_entry_desctiption):
            df_tmp = df_entry[df_entry["description"] == obj["description"]]
            if math.isclose(df_tmp["debit"].sum(),
                            df_tmp["credit"].sum(),
                            rel_tol=1e-5):
                res.append(df_tmp)
        if len(res) > 0:
            splited = pd.concat(res)
            df_duplicated = pd.concat([df_entry, splited])
            df_leave = df_duplicated.drop_duplicates(keep=False)
            if len(df_leave) > 0:
                res.append(df_leave)
            return res
        else:
            return [df_entry]
    else:
        return [df_entry]
Example #9
0
def add_same_and_opposite_subjects_nature_transactionvolume(
        session, df_xsz, records, grades, start_time, end_time):
    '''
    在序时账中添加对方科目/相同方科目/款项性质/交易金额(借方合计数)/合并借贷方名称/交易凭证发生次数合计
    :param df_xsz:序时账
    :param records:所有凭证记录
    :return:
    '''

    start_time = datetime.strptime(start_time, '%Y-%m-%d')
    end_time = datetime.strptime(end_time, '%Y-%m-%d')

    df_xsz_new = df_xsz.copy().set_index(
        ['month', 'vocher_type', 'vocher_num', 'subentry_num'])
    df_xsz_new = df_xsz_new.sort_index()
    df_xsz_new["same_subjects"] = ""
    df_xsz_new["opposite_subjects"] = ""
    df_xsz_new["entry_desc"] = ""
    df_xsz_new["transaction_volume"] = 0.00
    df_xsz_new["entry_classify_count"] = 0

    for record in records:
        df_tmp = df_xsz[(df_xsz["month"] == record["month"])
                        & (df_xsz["vocher_num"] == record["vocher_num"])
                        & (df_xsz["vocher_type"] == record["vocher_type"])]
        subjects = get_entry_subjects(df_tmp, "tb_subject")
        transaction_volume = df_tmp["debit"].sum()
        debit_subjects_list = subjects["debit"]
        credit_subjects_list = subjects["credit"]
        # 合并科目名称
        debit_subject_desc = "%".join(debit_subjects_list)
        credit_subjects_desc = "%".join(credit_subjects_list)
        entry_desc = debit_subject_desc + "@" + credit_subjects_desc
        entry_classify = session.query(EntryClassify).filter(
            EntryClassify.start_time == start_time,
            EntryClassify.end_time == end_time,
            EntryClassify.desc == entry_desc,
        ).one()
        entry_classify_count = entry_classify.number

        df_entry_debit = df_tmp[df_tmp["direction"] == "借"]
        df_entry_credit = df_tmp[df_tmp["direction"] == "贷"]
        for obj in gen_df_line(df_entry_debit):
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'same_subjects'] = json.dumps(debit_subjects_list,
                                                         ensure_ascii=False)
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'opposite_subjects'] = json.dumps(
                               credit_subjects_list, ensure_ascii=False)
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'transaction_volume'] = transaction_volume
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'entry_desc'] = entry_desc
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'entry_classify_count'] = entry_classify_count
            if obj["tb_subject"] in ["其他应收款", "其他应付款", "应交税费"]:
                nature = get_subject_nature(obj, debit_subjects_list,
                                            credit_subjects_list, df_tmp,
                                            grades)
                df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                obj['vocher_num'], obj['subentry_num']),
                               'nature'] = nature
        for obj in gen_df_line(df_entry_credit):
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'same_subjects'] = json.dumps(credit_subjects_list,
                                                         ensure_ascii=False)
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'opposite_subjects'] = json.dumps(
                               debit_subjects_list, ensure_ascii=False)
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'transaction_volume'] = transaction_volume
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'entry_desc'] = entry_desc
            df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                            obj['vocher_num'], obj['subentry_num']),
                           'entry_classify_count'] = entry_classify_count
            if obj["tb_subject"] in ["应付账款", "预付款项", "其他应收款", "其他应付款", "应交税费"]:
                nature = get_subject_nature(obj, debit_subjects_list,
                                            credit_subjects_list, df_tmp,
                                            grades)
                df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                obj['vocher_num'], obj['subentry_num']),
                               'nature'] = nature

    return df_xsz_new.reset_index()
def save_account_occur_times_to_db(engine, session, start_time, end_time):
    '''
    将往来款的发生时间放在数据库
    :param engine:
    :param session:
    :param start_time:
    :param end_time:
    :return:
    '''
    start_time = datetime.strptime(start_time, '%Y-%m-%d')
    end_time = datetime.strptime(end_time, '%Y-%m-%d')
    deleteAccountAge(session, start_time, end_time)
    # 获取调整分录
    df_adjustment = pd.read_sql(
        session.query(AduitAdjustment).filter(
            AduitAdjustment.year <= end_time.year,
            AduitAdjustment.month <= end_time.month).statement, engine)
    # 获取以前年度所有的序时账,合并审计调整分录
    df_xsz_all = pd.read_sql(
        session.query(ChronologicalAccount).filter(
            ChronologicalAccount.year <= end_time.year,
            ChronologicalAccount.month <= end_time.month).statement, engine)
    df_xsz_all = df_xsz_all.append(df_adjustment)
    df_xsz_all = df_xsz_all.sort_values(by=['record_time', 'vocher_num'],
                                        ascending=False)
    df_xsz_all["search_auxiliary"] = df_xsz_all["auxiliary"].str.replace(
        r'[\(\)]+', '')
    # 获取当年度的序时账,合并审计调整分录
    df_xsz = pd.read_sql(
        session.query(ChronologicalAccount).filter(
            ChronologicalAccount.year == end_time.year,
            ChronologicalAccount.month <= end_time.month).statement, engine)
    df_xsz = df_xsz.append(df_adjustment)
    df_xsz = df_xsz.sort_values(by=['record_time', 'vocher_num'],
                                ascending=False)
    df_xsz["search_auxiliary"] = df_xsz["auxiliary"].str.replace(
        r'[\(\)]+', '')
    # 获取科目余额表,并根据序时账重新计算科目余额表
    df_subject_balance = pd.read_sql(
        session.query(SubjectBalance).filter(
            SubjectBalance.start_time == start_time,
            SubjectBalance.end_time == end_time,
        ).statement, engine)
    df_subject_balance_new = recaculate_km(df_subject_balance, df_xsz,
                                           "audited")

    # 获取辅助核算明细表,并根据序时账重算辅助核算明细表
    df_auxiliary = pd.read_sql(
        session.query(Auxiliary).filter(
            Auxiliary.start_time == start_time,
            Auxiliary.end_time == end_time,
        ).statement, engine)
    # 部门辅助核算不包含
    df_auxiliary = df_auxiliary[~df_auxiliary["type_name"].str.contains("部门")]
    df_auxiliary_new = recaculate_auxiliary(df_auxiliary, df_xsz)

    for setting in settings:
        df_detail = get_subject_detail(df_subject_balance_new,
                                       df_auxiliary_new, setting["values"])
        df_detail["origin_subject"] = setting["name"]
        # 获取所有项目的发生时间
        for obj in gen_df_line(df_detail):
            occur_times = get_occour_times(obj, df_xsz_all)
            account_age = AccountAge(
                start_time=start_time,
                end_time=end_time,
                subject_num=obj["subject_num"],
                origin_subject=obj["origin_subject"],
                subject_name=obj["subject_name"],
                source=obj["source"],
                direction=obj["direction"],
                initial_amount=obj["initial_amount"],
                origin_debit=obj["origin_debit"],
                origin_credit=obj["origin_credit"],
                origin_terminal=obj["origin_terminal"],
                origin_terminal_value=obj["origin_terminal_value"],
                debit_amount=obj["debit_amount"],
                credit_amount=obj["credit_amount"],
                terminal_amount=obj["terminal_amount"],
                terminal_value=obj["terminal_value"],
                occour_times=json.dumps(occur_times, cls=DateEncoder))
            session.add(account_age)
        session.commit()
def get_profit_distribution(df_km, df_xsz, add_suggestion, start_time,
                            end_time, session, engine):
    '''
    分析利润分配科目
    :param df_km:
    :param df_xsz:
    :return:
    '''
    # 获取标准科目对照表
    df_std = pd.read_sql_table('subjectcontrast', engine)
    # 分析序时账分别填列
    # 获取利润分配的所有明细账
    # 获取利润分配的科目编码
    subject_num_profit = get_subject_num_by_name("利润分配", df_km)
    # 获取利润分配的所有凭证包含借贷方
    if subject_num_profit:
        df_profit_xsz = get_xsz_by_subject_num(df_xsz,
                                               grade=1,
                                               subject_num=subject_num_profit)
        df_this_year_profit_xsz = df_profit_xsz[df_profit_xsz["subject_name_1"]
                                                == "本年利润"]
        # 从利润分配凭证中减去本年利润结转类凭证
        for obj in gen_df_line(df_this_year_profit_xsz):
            df_profit_xsz = df_profit_xsz[~(
                (df_profit_xsz["month"] == obj["month"]) &
                (df_profit_xsz["vocher_num"] == obj["vocher_num"]) &
                (df_profit_xsz["vocher_type"] == obj["vocher_type"]))]
        # 检查利润分配-提取盈余公积
        # 获取利润分配凭证中的提取盈余公积的凭证
        subject_num_reserve = get_subject_num_by_name("盈余公积", df_km)
        df_xsz_reserve = pd.DataFrame()
        if subject_num_reserve:
            df_xsz_reserve = get_xsz_by_subject_num(
                df_profit_xsz, grade=1, subject_num=subject_num_reserve)

        # 检查利润分配-转为资本
        subject_num_paid_up_capital = get_subject_num_by_similar_name(
            "实收资本", df_km)
        if not subject_num_paid_up_capital:
            subject_num_paid_up_capital = get_subject_num_by_similar_name(
                "股本", df_km)
        subject_num_captial_reserve = get_subject_num_by_name("资本公积", df_km)
        subject_num_capital = []
        for item in [subject_num_paid_up_capital, subject_num_captial_reserve]:
            if item:
                subject_num_capital.append(item)
        df_xsz_capital = get_xsz_by_subject_num(
            df_profit_xsz, grade=1, subject_num=subject_num_capital)
        # 扣除调整分录
        df_xsz_capital = get_none_adjust_xsz(df_xsz_capital)

        # 分配股利
        subject_num_ividend_payable = get_subject_num_by_name("应付股利", df_km)
        subject_num_cash1 = get_subject_num_by_name("现金", df_km)
        subject_num_cash2 = get_subject_num_by_name("库存现金", df_km)
        subject_num_bank_deposit = get_subject_num_by_name("银行存款", df_km)
        subject_num_dividend = []
        for item in [
                subject_num_ividend_payable, subject_num_cash1,
                subject_num_cash2, subject_num_bank_deposit
        ]:
            if item:
                subject_num_dividend.append(item)
        df_xsz_dividend = get_xsz_by_subject_num(
            df_profit_xsz, grade=1, subject_num=subject_num_dividend)
        # 扣除调整分录
        df_xsz_dividend = get_none_adjust_xsz(df_xsz_dividend)

        # 利润调整1--以前年度损益调整
        subject_num_prior_year_income_adjustment = get_subject_num_by_name(
            "以前年度损益调整", df_km)
        df_xsz_adjustment = pd.DataFrame()
        if subject_num_prior_year_income_adjustment:
            df_xsz_adjustment = get_xsz_by_subject_num(
                df_profit_xsz,
                grade=1,
                subject_num=subject_num_prior_year_income_adjustment)
        df_profit_xsz_adjustment = df_xsz_adjustment[
            df_xsz_adjustment["subject_name_1"] == "以前年度损益调整"]
        # 利润调整2--未通过损益表项目直接计入本年利润
        df_none_profit_and_loss_xsz = get_not_through_profit_and_loss_to_this_year_profit(
            df_km, df_xsz, start_time, end_time, add_suggestion, session)

        # 本年利润
        subject_num_this_year_profit = get_subject_num_by_name("本年利润", df_km)
        df_xsz_this_year_profit = pd.DataFrame()
        if subject_num_this_year_profit:
            df_xsz_this_year_profit = get_xsz_by_subject_num(
                df_profit_xsz,
                grade=1,
                subject_num=subject_num_this_year_profit)
        df_has_check = pd.concat([
            df_xsz_this_year_profit, df_xsz_adjustment, df_xsz_dividend,
            df_xsz_capital, df_xsz_reserve
        ])
        df_has_check = df_has_check[["month", "vocher_num",
                                     "vocher_type"]].drop_duplicates()

        df_tmp = df_profit_xsz.copy()
        # 获取未检查的可能的调整分录
        for obj in gen_df_line(df_has_check):
            df_tmp = df_tmp[~((df_tmp["month"] == obj["month"]) &
                              (df_tmp["vocher_num"] == obj["vocher_num"]) &
                              (df_tmp["vocher_type"] == obj["vocher_type"]))]
        # 利润调整3- -直接计入利润分配科目
        df_rest_profit = pd.DataFrame()
        if len(df_tmp) > 0:
            # 扣除掉损益结转类科目
            # (1)如果含有非损益类科目,则不是损益结转凭证
            # (2)如果不含有非损益类科目,但损益类科目方向不相反(费用类为借方,收入类为贷方,则认定为调整分录)
            profit_and_loss = df_tmp[df_tmp["subject_num"].str.startswith("6")]
            profit_and_loss = pd.merge(profit_and_loss,
                                       df_std,
                                       how="inner",
                                       left_on='subject_name_1',
                                       right_on="origin_subject")
            for obj in gen_df_line(profit_and_loss):
                if (obj["direction"] == "借" and abs(obj["credit"]) > 0) or (
                        obj["direction"] == "贷" and abs(obj["debit"]) > 0):
                    df_tmp = df_tmp[~(
                        (df_tmp["month"] == obj["month"]) &
                        (df_tmp["vocher_num"] == obj["vocher_num"]) &
                        (df_tmp["vocher_type"] == obj["vocher_type"]))]
            df_rest_profit = df_tmp[df_tmp["subject_name_1"] != "利润分配"]
        df_profit_and_other_xsz_adjustment = pd.concat([
            df_rest_profit, df_profit_xsz_adjustment,
            df_none_profit_and_loss_xsz
        ])
        return df_profit_and_other_xsz_adjustment
    else:
        raise Exception("公司没有设置利润分配科目")
def add_std_not_exist_subject(df_km, df_std, session):
    '''
    实现步骤:
    按照科目编码对科目余额表进行升序排列
    # 资产判断
    #如果在流动资产内,则为流动资产
    # 如果在所有流动资产之后,在所有非流动资产之前,分类为流动资产
    # 如果在非流动资产内,则为非流动资产
    # 负债判断
    # 同流动资产和非流动资产
    # 权益类
    # 收入类
    # 成本费用类
    :param df_km:
    :param df_std:
    :return:同时修改TBsubject和subject_contrast
    '''
    df_km = df_km.copy()
    df_std = df_std.copy()

    # 按照科目编码对科目余额表进行升序排列
    df_km = df_km.sort_values(by=['subject_num'])
    std_not_match_subject = {"坏账准备", "本年利润", "利润分配", "以前年度损益调整"}
    # 获取一级科目余额表,用于检查是否存在未识别的一级科目,且至少在期初/期末或本期借贷方有发生额
    df_km_first_subject = get_not_null_df_km(df_km, 1)
    # 检查是否有未识别的一级会计科目
    df_km_first_subject_merge_std = pd.merge(df_km_first_subject,
                                             df_std,
                                             how="left",
                                             left_on='subject_name',
                                             right_on="origin_subject")
    df_km_first_subject_not_match = df_km_first_subject_merge_std[
        df_km_first_subject_merge_std['coefficient'].isna()]
    diff_subject_names = set(df_km_first_subject_not_match['subject_name'])
    res_diff_subject_names = diff_subject_names - std_not_match_subject
    if len(res_diff_subject_names) == 0:
        # 没有未匹配的以及科目
        return
    # 遍历每一个标准科目表中不存在的科目,分别增加科目对照表和TBSubject
    for obj in gen_df_line(df_km_first_subject_not_match):
        if obj["subject_name"] in std_not_match_subject:
            continue
        index_num = df_km_first_subject_merge_std[
            df_km_first_subject_merge_std["subject_name"] ==
            obj["subject_name"]].index.values[0]
        last_class = df_km_first_subject_merge_std.at[index_num - 1,
                                                      "second_class"]
        next_class = df_km_first_subject_merge_std.at[index_num + 1,
                                                      "second_class"]
        if obj["subject_type"] == "资产":
            if (next_class == "流动资产") or (next_class == "非流动资产"
                                          and last_class == "流动资产"):
                this_class = "流动资产"
                tb_obj = session.query(TBSubject).filter(
                    TBSubject.order > 100, TBSubject.order < 200).order_by(
                        TBSubject.order.desc()).first()
                order = tb_obj.order
                #     增加流动资产和总资产
                modify_subjects = ["流动资产合计", "资产总计"]
                if obj["direction_x"] == "借":
                    modify_all_tb(modify_subjects, obj["subject_name"], "+",
                                  session)
                else:
                    modify_all_tb(modify_subjects, obj["subject_name"], "-",
                                  session)
            else:
                this_class = "非流动资产"
                tb_obj = session.query(TBSubject).filter(
                    TBSubject.order > 200, TBSubject.order < 300).order_by(
                        TBSubject.order.desc()).first()
                order = tb_obj.order
                #     增加非流动资产和总资产
                modify_subjects = ["非流动资产合计", "资产总计"]
                if obj["direction_x"] == "借":
                    modify_all_tb(modify_subjects, obj["subject_name"], "+",
                                  session)
                else:
                    modify_all_tb(modify_subjects, obj["subject_name"], "-",
                                  session)
            first_class = "资产"
        elif obj["subject_type"] == "负债":
            if (next_class == "流动负债") or (next_class == "非流动负债"
                                          and last_class == "非流动负债"):
                this_class = "流动负债"
                tb_obj = session.query(TBSubject).filter(
                    TBSubject.order > 300, TBSubject.order < 400).order_by(
                        TBSubject.order.desc()).first()
                order = tb_obj.order
                #     增加流动负债和总负债/负债和所有者权益
                modify_subjects = ["流动负债合计", "负债合计", "负债和股东权益总计"]
                if obj["direction_x"] == "贷":
                    modify_all_tb(modify_subjects, obj["subject_name"], "+",
                                  session)
                else:
                    modify_all_tb(modify_subjects, obj["subject_name"], "-",
                                  session)
            else:
                this_class = "非流动负债"
                tb_obj = session.query(TBSubject).filter(
                    TBSubject.order > 400, TBSubject.order < 500).order_by(
                        TBSubject.order.desc()).first()
                order = tb_obj.order
                #          增加非流动负债和总负债/负债和所有者权益
                modify_subjects = ["非流动负债合计", "负债合计", "负债和股东权益总计"]
                if obj["direction_x"] == "贷":
                    modify_all_tb(modify_subjects, obj["subject_name"], "+",
                                  session)
                else:
                    modify_all_tb(modify_subjects, obj["subject_name"], "-",
                                  session)
            first_class = "负债"
        elif obj["subject_type"] == "权益":
            if ("股本" in obj['subject_name']) or ("实收资本"
                                                 in obj["subject_name"]):
                subjectcontrast = SubjectContrast(
                    origin_subject=obj["subject_name"],
                    tb_subject="股本(实收资本)",
                    fs_subject="股本",
                    coefficient=1,
                    direction="贷",
                    first_class="权益",
                    second_class="所有者权益")
                session.add(subjectcontrast)
                session.commit()
                continue
            this_class = "所有者权益"
            first_class = "权益"
            tb_obj = session.query(TBSubject).filter(
                TBSubject.order > 500, TBSubject.order < 600).order_by(
                    TBSubject.order.desc()).first()
            order = tb_obj.order
            #     增加所有者权益和负债和所有者权益
            modify_subjects = ["归属于母公司股东权益合计", "股东权益合计", "负债和股东权益总计"]
            if obj["direction_x"] == "贷":
                modify_all_tb(modify_subjects, obj["subject_name"], "+",
                              session)
            else:
                modify_all_tb(modify_subjects, obj["subject_name"], "-",
                              session)
        elif obj["subject_type"] == "成本":
            this_class = "流动资产"
            first_class = "资产"
            tb_obj = session.query(TBSubject).filter(
                TBSubject.order > 100, TBSubject.order < 200).order_by(
                    TBSubject.order.desc()).first()
            order = tb_obj.order
            #     增加流动资产和总资产
            modify_subjects = ["流动资产合计", "资产总计"]
            if obj["direction_x"] == "借":
                modify_all_tb(modify_subjects, obj["subject_name"], "+",
                              session)
            else:
                modify_all_tb(modify_subjects, obj["subject_name"], "-",
                              session)
        elif obj["subject_type"] == "损益":
            if obj["direction"] == "贷":
                if (next_class == "收入") or (next_class == "成本费用"):
                    this_class = "收入"
                    tb_obj = session.query(TBSubject).filter(
                        TBSubject.order > 600, TBSubject.order < 700).order_by(
                            TBSubject.order.desc()).first()
                    order = tb_obj.order
                    #     增加 一、营业总收入/三、营业利润(亏损以“-”号填列)/四、利润总额(亏损总额以“-”号填列)/五、净利润(净亏损以“-”号填列)/
                    #  九、可供分配的利润/ 十、可供投资者分配的利润/ 十一、未分配利润/未分配利润/归属于母公司股东权益合计/股东权益合计/负债和股东权益总计
                    modify_subjects = [
                        "一、营业总收入", "三、营业利润(亏损以“-”号填列)", "四、利润总额(亏损总额以“-”号填列)",
                        "五、净利润(净亏损以“-”号填列)", "九、可供分配的利润", "十、可供投资者分配的利润",
                        "十一、未分配利润", "未分配利润", "归属于母公司股东权益合计", "股东权益合计",
                        "负债和股东权益总计"
                    ]
                    if obj["direction_x"] == "贷":
                        modify_all_tb(modify_subjects, obj["subject_name"],
                                      "+", session)
                    else:
                        modify_all_tb(modify_subjects, obj["subject_name"],
                                      "-", session)
                else:
                    this_class = "收益"
                    tb_obj = session.query(TBSubject).filter(
                        TBSubject.order > 800, TBSubject.order < 900).order_by(
                            TBSubject.order.desc()).first()
                    order = tb_obj.order
                    #     增加 三、营业利润(亏损以“-”号填列)/四、利润总额(亏损总额以“-”号填列)/五、净利润(净亏损以“-”号填列)/
                    #  九、可供分配的利润/ 十、可供投资者分配的利润/ 十一、未分配利润/未分配利润/归属于母公司股东权益合计/股东权益合计/负债和股东权益总计
                    modify_subjects = [
                        "三、营业利润(亏损以“-”号填列)", "四、利润总额(亏损总额以“-”号填列)",
                        "五、净利润(净亏损以“-”号填列)", "九、可供分配的利润", "十、可供投资者分配的利润",
                        "十一、未分配利润", "未分配利润", "归属于母公司股东权益合计", "股东权益合计",
                        "负债和股东权益总计"
                    ]
                    if obj["direction_x"] == "贷":
                        modify_all_tb(modify_subjects, obj["subject_name"],
                                      "+", session)
                    else:
                        modify_all_tb(modify_subjects, obj["subject_name"],
                                      "-", session)
            else:
                this_class = "成本费用"
                tb_obj = session.query(TBSubject).filter(
                    TBSubject.order > 700, TBSubject.order < 800).order_by(
                        TBSubject.order.desc()).first()
                order = tb_obj.order
                #     增加 三、营业利润(亏损以“-”号填列)/四、利润总额(亏损总额以“-”号填列)/五、净利润(净亏损以“-”号填列)/
                #  九、可供分配的利润/ 十、可供投资者分配的利润/ 十一、未分配利润/未分配利润/归属于母公司股东权益合计/股东权益合计/负债和股东权益总计
                modify_subjects = [
                    "三、营业利润(亏损以“-”号填列)", "四、利润总额(亏损总额以“-”号填列)",
                    "五、净利润(净亏损以“-”号填列)", "九、可供分配的利润", "十、可供投资者分配的利润",
                    "十一、未分配利润", "未分配利润", "归属于母公司股东权益合计", "股东权益合计", "负债和股东权益总计"
                ]
                if obj["direction_x"] == "贷":
                    modify_all_tb(modify_subjects, obj["subject_name"], "+",
                                  session)
                else:
                    modify_all_tb(modify_subjects, obj["subject_name"], "-",
                                  session)
            first_class = "损益"
        else:
            raise Exception("类型识别错误,请检查类别设置是否正确")

        #  增加类别
        fs_subject = input("{}请输入报表对应的名称{}".format(
            obj["subject_name"], df_std[df_std["second_class"] == this_class]
            ["fs_subject"].unique()))
        subjectcontrast = SubjectContrast(origin_subject=obj["subject_name"],
                                          tb_subject=obj['subject_name'],
                                          fs_subject=fs_subject,
                                          coefficient=1,
                                          direction=obj["direction_x"],
                                          first_class=first_class,
                                          second_class=this_class)
        session.add(subjectcontrast)
        tbsubject = TBSubject(show=obj["subject_name"],
                              subject=obj["subject_name"],
                              direction=obj["direction_x"],
                              order=order + 1)
        session.add(tbsubject)
        session.commit()
def check_profit_subject_dirction(df_km, df_xsz, engine, add_suggestion,
                                  start_time, end_time, session):
    '''
    检查序时账中的损益科目是否核算方向正确,不正确的调整方向
    :param df_km: 科目余额表
    :param df_xsz: 待修改的序时账
    :return: 返回调整后的序时账
    '''
    # 检查是否所有的损益类项目的核算都正确
    # 第一步:获取所有损益类核算项目
    # 第二部:获取所有损益类核算项目的标准方向
    # 第三部:检查是否存在相反方向核算且不属于损益结转的情况
    # 第四步:将核算方向相反的凭证予以调整
    df_xsz_new = df_xsz.copy().set_index(
        ['month', 'vocher_type', 'vocher_num', 'subentry_num'])
    # 第一步:获取所有损益类核算项目
    df_km_first_subject = df_km[df_km['subject_gradation'] == 1]
    df_km_first_subject_profit = df_km_first_subject[
        df_km_first_subject["subject_num"].str.startswith('6')]
    df_km_first_subject_profit = df_km_first_subject_profit[[
        'subject_num', 'subject_name'
    ]]
    # 第二部:获取所有损益类核算项目的标准方向
    df_std = pd.read_sql_table('subjectcontrast', engine)
    df_km_first_subject_profit_direction = pd.merge(df_km_first_subject_profit,
                                                    df_std,
                                                    how="inner",
                                                    left_on='subject_name',
                                                    right_on="origin_subject")
    df_km_first_subject_profit_direction = df_km_first_subject_profit_direction[
        ["subject_num", "subject_name", "direction"]]
    # 所有的损益类凭证
    df_xsz_profit = df_xsz[df_xsz['subject_name_1'].isin(
        df_km_first_subject_profit_direction['subject_name'])]
    # 合并损益类凭证列表和损益类核算项目的标准方向
    df_xsz_profit = pd.merge(df_xsz_profit,
                             df_km_first_subject_profit_direction,
                             how="left",
                             left_on="subject_name_1",
                             right_on="subject_name",
                             suffixes=('_x', ''))
    # 获取核算相反的凭证
    df_xsz_profit_reverse = df_xsz_profit[(
        (df_xsz_profit["direction"] == "借") &
        (df_xsz_profit["credit"].abs() > 1e-5)) | (
            (df_xsz_profit["direction"] == "贷") &
            (df_xsz_profit["debit"].abs() > 1e-5))]
    df_xsz_profit_reverse_record = df_xsz_profit_reverse[[
        "month", "vocher_num", "vocher_type"
    ]].drop_duplicates()
    # 获取相反凭证的记录
    reverse_records = df_xsz_profit_reverse_record.to_dict('records')
    # 获取相反凭证的完整借贷方
    df_xsz_profit_reverse = pd.merge(df_xsz,
                                     df_xsz_profit_reverse_record,
                                     how="inner",
                                     on=["month", "vocher_num", "vocher_type"])
    # 第三部:检查是否存在相反方向核算且不属于损益结转的情况
    # 检查每一笔相反凭证中是否包含本年利润,如果包含则是正常的结转损益,不用理会
    for record in reverse_records:
        df_tmp = df_xsz_profit_reverse[
            (df_xsz_profit_reverse["month"] == record["month"])
            & (df_xsz_profit_reverse["vocher_num"] == record["vocher_num"])
            & (df_xsz_profit_reverse["vocher_type"] == record["vocher_type"])]
        # 检查凭证中是否包含本年利润,如果不包含则调整序时账
        if (not df_tmp["subject_name_1"].str.contains(
                '本年利润', regex=False).any()) and (
                    not df_tmp["subject_name_1"].str.contains(
                        '利润分配', regex=False).any()):
            # 第四部:修改序时账
            # 合并标准方向
            df_tmp = pd.merge(df_tmp,
                              df_km_first_subject_profit_direction,
                              left_on="subject_num_1",
                              right_on="subject_num",
                              how="left",
                              suffixes=("", "_y"))
            for obj in gen_df_line(df_tmp):
                if obj['direction'] == "借" and abs(obj['credit']) > 1e-5:
                    # 借贷方金额互换
                    tmp = df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                          obj['vocher_num'],
                                          obj['subentry_num']), 'credit']
                    df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                    obj['vocher_num'], obj['subentry_num']),
                                   'debit'] = -tmp
                    df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                    obj['vocher_num'], obj['subentry_num']),
                                   'credit'] = 0.00

                    tmp1 = df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                           obj['vocher_num'],
                                           obj['subentry_num']),
                                          'credit_foreign_currency']
                    df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                    obj['vocher_num'], obj['subentry_num']),
                                   'debit_foreign_currency'] = -tmp1
                    df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                    obj['vocher_num'], obj['subentry_num']),
                                   'credit_foreign_currency'] = 0.00
                    #    提建议
                    add_suggestion(
                        kind="会计处理",
                        content=
                        "{}年{}月{}-{}号凭证损益类项目记账不符合规范,建议收入类科目发生时计入贷方,费用类项目发生时计入借方"
                        .format(obj['year'], obj['month'], obj['vocher_type'],
                                obj['vocher_num']),
                        start_time=start_time,
                        end_time=end_time,
                        session=session)
                elif obj['direction'] == "贷" and abs(obj['debit']) > 1e-5:
                    # 借贷方金额互换
                    tmp = df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                          obj['vocher_num'],
                                          obj['subentry_num']), 'debit']
                    df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                    obj['vocher_num'], obj['subentry_num']),
                                   'credit'] = -tmp
                    df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                    obj['vocher_num'], obj['subentry_num']),
                                   'debit'] = 0.00
                    tmp1 = df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                           obj['vocher_num'],
                                           obj['subentry_num']),
                                          'debit_foreign_currency']
                    df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                    obj['vocher_num'], obj['subentry_num']),
                                   'credit_foreign_currency'] = -tmp1
                    df_xsz_new.loc[(obj['month'], obj['vocher_type'],
                                    obj['vocher_num'], obj['subentry_num']),
                                   'debit_foreign_currency'] = 0.00
                    #    提建议
                    add_suggestion(
                        kind="会计处理",
                        content=
                        "{}年{}月{}-{}号凭证损益类项目记账不符合规范,建议收入类科目发生时计入贷方,费用类项目发生时计入借方"
                        .format(obj['year'], obj['month'], obj['vocher_type'],
                                obj['vocher_num']),
                        start_time=start_time,
                        end_time=end_time,
                        session=session)
    df_xsz_new = df_xsz_new.reset_index()
    return df_xsz_new