人财事物信息化 - company.py

核心功能模块

  1. 公司管理 (company.py)

    • Company 继承自 NestedSet,支持树形结构管理(父子公司)。
    • 功能:
    • 验证逻辑: 校验公司缩写、默认账户、货币一致性、库存策略。
    • 默认数据初始化: 自动创建账户、仓库、部门、成本中心。
    • 多层级支持: 通过嵌套集模型管理公司层级关系。
    • 删除保护: 检查未完成交易后允许删除,清理关联数据(账户、仓库、BOM等)。
  2. 财务管理

    • 会计科目: 自动创建基于模板的科目表(如应收账款、应付账款)。
    • 税务配置: 支持国家特定税种模板(如 setup_taxes_and_charges)。
    • 货币管理: 强制默认货币与交易账户一致,处理汇率差异。
  3. 库存管理

    • 仓库管理: 默认创建“所有仓库”“库存”等层级仓库。
    • 库存计价: 启用永续库存(Perpetual Inventory)时验证默认库存账户。
  4. 多国适配

    • 区域化配置: 按国家安装本地化设置(如中国税种、财务报告格式)。
    • 地址管理: 支持主地址和运输地址分离,动态获取默认地址。
  5. 交易与审计

    • 时间线数据: 记录年度交易历史,用于仪表盘分析。
    • 交易删除请求: 通过 Transaction Deletion Record 安全删除历史数据。

技术实现

  1. 代码结构

    • 模块化设计: 按功能划分目录(如 accounts, buying, crm)。
    • 继承与扩展: 使用 Frappe 框架的 NestedSet 实现树形结构。
    • 钩子方法: on_update, validate, on_trash 处理生命周期事件。
  2. 关键方法

    • 数据初始化: create_default_accounts, create_default_warehouses
    • 验证逻辑: validate_currency, validate_perpetual_inventory
    • 工具方法: get_default_company_address, update_transactions_annual_history
  3. 依赖与集成

    • Frappe 框架: 基于 Frappe 的模型、权限、缓存机制。
    • 外部服务: 支持支付宝/微信支付(需配置密钥)、SMTP 邮件服务。

使用场景

  • 多公司集团: 通过父子公司结构管理跨地域业务。
  • 财务合规: 符合不同国家的会计标准(如增值税处理)。
  • 库存控制: 永续库存模式支持实时库存价值跟踪。
  • 审计追踪: 记录所有交易的年度历史,便于合规审计。

扩展与定制

  • 区域适配: 通过 regional 目录添加本地化模块。
  • 自定义字段: 利用 Property Setter 扩展模型字段。
  • 工作流: 定义审批流程(如预算审批角色)。

注意事项

  • 数据安全: 删除公司前需确保无关联交易,避免数据丢失。
  • 性能优化: 大宗数据处理时需考虑缓存(如 clear_defaults_cache)。
  • 依赖管理: 确保 Frappe 及第三方库版本兼容性。

总结

此仓库为 ERPNext 的定制版本,强化了公司管理与财务模块,支持多国业务适配,适合中大型企业需要高度可定制化及合规要求的场景。通过 Frappe 框架的扩展性,开发者可快速添加新功能或适配本地规范。

详解class类和def函数

 深入解读 `company.py` 中的 `Company` 类及核心方法

 1. 类定义与继承
class Company(NestedSet):
     begin: auto-generated types
     ... (自动生成的字段定义)
     end: auto-generated types
    nsm_parent_field = "parent_company"/
- 技术实现: - 继承 `NestedSet` 类:实现树形结构(父子层级),用于管理多层级公司(如集团与子公司)。 - `nsm_parent_field`:指定父公司字段为 `parent_company`,框架自动处理层级关系(如 `lft`、`rgt` 字段更新)。 - 业务逻辑: - 支持集团化企业的组织架构管理,确保子公司数据隔离与继承(如共享科目表)。 --- 2. 关键方法解析 `validate_abbr` 方法
def validate_abbr(self):
    if not self.abbr:
        self.abbr = "".join(c0 for c in self.company_name.split()).upper()
     校验唯一性及非空
- 技术实现: - 自动生成公司缩写(如 "Frappe Tech" → "FT"),通过数据库查询确保唯一性。 - 使用 `frappe.throw` 抛出校验异常,阻止无效数据保存。 - 业务逻辑: - 缩写用于生成账户、仓库等编号前缀,确保系统内标识唯一性。 `on_update` 方法
def on_update(self):
    NestedSet.on_update(self)
    if not frappe.db.exists("Account", {"company": self.name}):
        self.create_default_accounts()
    self.create_default_warehouses()
     ... (其他初始化操作)
- 技术实现: - 调用 `NestedSet.on_update` 更新树形结构。 - 初始化默认账户(Chart of Accounts)、仓库、部门。 - 使用 `frappe.flags` 控制初始化逻辑(如 `ignore_chart_of_accounts` 跳过科目表生成)。 - 业务逻辑: - 新公司创建时自动生成财务、库存基础数据,减少手动配置。 `create_default_accounts` 方法
def create_default_accounts(self):
    from erpnext.accounts.doctype.account.chart_of_accounts import create_charts
    create_charts(self.name, self.chart_of_accounts, self.existing_company)
- 技术实现: - 调用 `create_charts` 生成标准科目表(如资产、负债、收入、支出)。 - 若选择基于现有公司(`existing_company`),复制其科目表结构。 - 业务逻辑: - 标准化财务数据初始化,支持多公司共享科目模板。 `validate_currency` 方法
def validate_currency(self):
    if self.default_currency != self.previous_default_currency:
        if self.check_if_transactions_exist():
            frappe.throw(_("Cannot change currency after transactions exist"))
- 技术实现: - 检查是否存在历史交易(通过 `check_if_transactions_exist` 查询多个单据表)。 - 使用 `previous_default_currency` 记录原始值,防止货币更改导致财务数据错乱。 - 业务逻辑: - 确保财务数据货币一致性,避免历史交易因货币变更产生计算错误。 `on_trash` 方法
def on_trash(self):
     删除关联数据:账户、仓库、部门等
    frappe.db.sql("delete from tabAccount where company=%s", self.name)
     ... (其他删除操作)
- 技术实现: - 级联删除公司相关数据(账户、仓库、BOM 等),需先检查是否存在未删除交易。 - 使用事务性 SQL 确保数据完整性。 - 业务逻辑: - 防止误删公司导致数据残留,确保系统数据干净。 --- 3. 核心业务逻辑实现 树形结构管理 - 技术实现: - `NestedSet` 维护 `lft` 和 `rgt` 字段,通过 `rebuild_tree` 方法重建层级。 - 示例:`parent_company` 变更时触发 `on_update` 更新子树。 - 业务逻辑: - 支持灵活调整组织架构(如子公司升级为独立公司)。 多国税务适配
def install_country_fixtures(company, country):
    try:
        module = f"erpnext.regional.{frappe.scrub(country)}.setup"
        frappe.get_attr(f"{module}.setup")(company)
- 技术实现: - 动态加载国家模块(如 `india.setup`),执行税务模板初始化。 - 异常处理提示用户联系支持,增强鲁棒性。 - 业务逻辑: - 快速适配不同国家的增值税、发票规则,满足全球化需求。 库存与财务集成
def validate_perpetual_inventory(self):
    if self.enable_perpetual_inventory and not self.default_inventory_account:
        frappe.msgprint(_("Set default inventory account"))
- 技术实现: - 校验是否配置库存账户,通过 `enable_perpetual_inventory` 控制库存计价方式。 - 影响 `Stock Ledger Entry` 和 `GL Entry` 的自动过账。 - 业务逻辑: - 实现库存价值实时更新(永续盘存)或定期调整(定期盘存)。 --- 4. 工具方法与辅助逻辑 `get_default_company_address` 方法
def get_default_company_address(name, sort_key="is_primary_address"):
     SQL 查询默认地址,按 sort_key 排序
- 技术实现: - 使用 `Dynamic Link` 关联公司与地址,通过 `is_primary_address` 或 `is_shipping_address` 标记优先级。 - 业务逻辑: - 自动化单据地址填充(如销售订单发货地址),提升操作效率。 `update_transactions_annual_history` 方法
def update_transactions_annual_history(company):
    history = get_all_transactions_annual_history(company)
    frappe.db.set_value("Company", company, "transactions_annual_history", json.dumps(history))
- 技术实现: - 聚合近一年交易数据(报价单、订单、发票等),存储为 JSON 供仪表盘展示。 - 业务逻辑: - 提供公司活跃度分析,辅助决策层评估业务趋势。 --- 总结 - 技术架构: - 基于 Frappe 框架的元数据驱动模型,结合嵌套集实现高效树形查询。 - 模块化设计(如 `regional` 目录分离国家特定逻辑),便于扩展。 - 业务设计: - 自动化初始化减少部署成本,严格校验确保数据合规。 - 多层级公司管理支持复杂组织结构,税务/库存模块深度集成。 - 扩展性**: - 通过 `hooks` 和 `override` 机制可定制国家模块或财务规则。

中国本地化会计税务实现

以下是基于 ERPNext 框架通过 hooks 和 override 机制实现中国会计准则和税务规则的代码示例。所有代码需在自定义 App (如 china_compliance) 中实现。


  1. 会计科目表适配 (中国准则)

    1.1 覆盖默认科目表 (hooks.py)

 hooks.py
regional_overrides = {
    "China": {
        "company": {
            "on_setup": "china_compliance.regional.china.setup.create_china_chart_of_accounts"
        },
        "Account": {
            "tree_method": "china_compliance.regional.china.account.get_china_account_children"
        }
    }
}

country_wise_accounting = {
    "China": {
        "account_name": "China Accounting Standards",
        "chart_of_accounts": "China Standard Chart"
    }
}

1.2 自定义科目表结构 (china/account.py)

 china_compliance/regional/china/account.py
def get_china_account_children(parent=None, company=None):
    """返回中国准则下的科目层级"""
    return 
        {
            "account_name": "资产类",
            "is_group": 1,
            "account_type": "Asset",
            "accounts": 
                {"account_name": "货币资金", "account_number": "1001"},
                {"account_name": "应收账款", "account_number": "1122"}

        },
        {
            "account_name": "负债类",
            "is_group": 1,
            "account_type": "Liability",
            "accounts": 
                {"account_name": "应付账款", "account_number": "2202"},
                {"account_name": "应交税费", "account_number": "2221"}

        }

  1. 增值税处理 (VAT)

    2.1 覆盖销售发票计税逻辑

 china_compliance/overrides/sales_invoice.py
from erpnext.controllers.sales_and_purchase_return import SalesInvoice

class ChinaSalesInvoice(SalesInvoice):
    def validate_taxes(self):
        """中国增值税计算规则 (13%,9%,6%)"""
        for tax in self.taxes:
            if tax.account_head == "应交税费-应交增值税(销项)":
                tax.tax_amount = self.net_total * tax.rate / 100

         调用原始方法进行其他验证
        super(ChinaSalesInvoice, self).validate_taxes()

2.2 增值税发票生成接口

// china_compliance/public/js/e_invoice.js
frappe.ui.form.on('Sales Invoice', {
    before_submit: function(frm) {
        // 调用税务局发票接口
        frappe.call({
            method: "china_compliance.api.generate_e_invoice",
            args: { doc: frm.doc },
            callback: function(response) {
                frm.set_value("e_invoice_number", response.message.invoice_no);
            }
        });
    }
});

  1. 税务报表定制

    3.1 增值税申报表 (doctype/vat_return.py)

 china_compliance/doctype/vat_return/vat_return.py
def get_vat_payable(self):
    """计算应纳增值税额"""
    output_tax = frappe.db.sql("""
        SELECT SUM(base_tax_amount) 
        FROM `tabSales Taxes and Charges`
        WHERE parenttype='Sales Invoice' 
        AND tax_type='Output'
        AND posting_date BETWEEN %s AND %s
    """, (self.from_date, self.to_date))00 or 0

    input_tax = frappe.db.sql("""
        SELECT SUM(base_tax_amount) 
        FROM `tabPurchase Taxes and Charges`
        WHERE parenttype='Purchase Invoice' 
        AND tax_type='Input'
        AND posting_date BETWEEN %s AND %s
    """, (self.from_date, self.to_date))00 or 0

    self.vat_payable = output_tax - input_tax

3.2 报表模板 (vat_return.json)

{
    "name": "VAT Return",
    "doctype": "Print Format",
    "html": """
        <div class="text-center">
            <h2>增值税纳税申报表</h2>
            <p>税款所属期: {{ doc.from_date }} 至 {{ doc.to_date }}</p>
        </div>
        <table class="table table-bordered">
            <tr>
                <td>销项税额</td>
                <td>{{ doc.output_tax }}</td>
            </tr>
            <tr>
                <td>进项税额</td>
                <td>{{ doc.input_tax }}</td>
            </tr>
            <tr class="text-bold">
                <td>应纳税额</td>
                <td>{{ doc.vat_payable }}</td>
            </tr>
        </table>
    """
}

  1. 固定资产处理

    4.1 固定资产折旧方法覆盖

 china_compliance/overrides/asset.py
from erpnext.assets.doctype.asset.depreciation import calculate_depreciation

def china_straight_line_method(asset):
    """中国直线法折旧计算"""
    if asset.calculate_depreciation == "China Straight Line":
        depreciation_amount = (asset.gross_purchase_amount - asset.expected_salvage_value) / asset.total_number_of_depreciations
        return depreciation_amount

calculate_depreciation = china_straight_line_method

  1. 银行对账单格式

    5.1 中国银行对账单导入器

 china_compliance/bank_integration/cn_bank_statement.py
def parse_cn_bank_statement(file_path):
    """解析中国银行标准格式对账单"""
    with open(file_path, "r", encoding="gbk") as f:
        lines = f.readlines()
        for line in lines6::   跳过标题行
            fields = line.split('|')
            yield {
                "date": fields0,
                "amount": float(fields3),
                "description": fields4.strip()
            }

关键配置项

  1. 科目表映射 (china_account_map.json):
{
    "default_accounts": {
        "default_receivable_account": "应收账款",
        "default_payable_account": "应付账款",
        "default_tax_account": "应交税费-应交增值税"
    }
}
  1. 税率配置 (china_tax_templates.json):
{
    "tax_templates": 
        {
            "title": "增值税13%",
            "tax_type": "Sales",
            "account_head": "应交税费-应交增值税(销项)",
            "rate": 13.0
        },
        {
            "title": "增值税进项",
            "tax_type": "Purchase",
            "account_head": "应交税费-应交增值税(进项)",
            "rate": 13.0
        }

}

部署说明

  1. 创建自定义 App:
bench new-app china_compliance
  1. apps.txt 添加:
china_compliance
  1. 通过钩子覆盖核心功能:
 hooks.py
override_doctype_class = {
    "Sales Invoice": "china_compliance.overrides.sales_invoice.ChinaSalesInvoice",
    "Purchase Invoice": "china_compliance.overrides.purchase_invoice.ChinaPurchaseInvoice"
}
  1. 安装中国地区包:
bench --site sitename install-app china_compliance
bench migrate

以上代码实现了中国特有的财务处理逻辑,包括但不限于:

  • 符合中国财政部的科目结构
  • 增值税专用发票生成接口
  • 金税三期标准的税务申报表
  • 符合中国会计准则的折旧计算
  • 国内银行对账单格式解析

实际部署时需要根据具体税务局接口规范调整实现细节。建议参考国家税务总局发布的《电子发票技术规范》进行深度定制。

Discard
Save
Review Changes ← Back to Content
Message Status Space Raised By Last update on