资讯动态

ERPNext HR模块容器化部署实战:Docker Compose一键落地指南

发布时间:2026/10/26 2:48:58 来源:尧图企业网站定制
1. 项目概述为什么一个ERP系统要走容器化安装这条路“【REP】hrms-ERPNext 容器安装配置”这个标题里藏着三个关键信号REP很可能是内部项目代号或版本标识、hrmsHuman Resource Management System人力资源模块先行的业务定位、ERPNext 容器安装配置技术实现路径明确指向Docker生态。这不是一次简单的软件部署而是一次面向中小组织数字化基建的轻量化重构——它绕开了传统ERP动辄数月的服务器环境适配、依赖冲突调试和权限纠缠把整套包含HR、财务、库存、项目管理的开源ERP系统压缩进几个可复现、可迁移、可快照的容器镜像里。我最早接触ERPNext是在某高校后勤处的一个小型资产与工单管理系统改造中。当时他们用的是0.23版源码直装光是Python 3.8和Node.js 14的版本对齐就卡了三天MySQL 5.7升级到8.0后又因默认认证插件不兼容导致整个bench init失败。后来换成Docker Compose方案从拉镜像到访问Web界面全程不到12分钟且所有配置项都固化在yaml文件里——运维同事改个数据库密码只需要改一行env变量连SSH都不用登。这就是容器化最实在的价值把“能不能跑起来”这个不确定性问题变成“配置对不对”的确定性问题。hrms作为切入点也极有讲究。ERPNext的HR模块天然具备低侵入、高可见、见效快的特点员工入职流程自动化、考勤数据自动同步、薪资计算模板可配置这些功能不需要打通全部业务线就能独立上线验证。相比一上来就硬刚财务总账或生产BOMhrms是组织愿意为容器化买单的第一个理由。而【REP】这个前缀大概率代表“Rapid Enablement Platform”——强调快速启用能力而非大而全的定制开发。所以这篇内容不是教你怎么从零写Dockerfile而是聚焦于如何用最小认知成本让一套开箱即用的hrms-ERPNext容器环境在你手头的笔记本、测试服务器或云主机上稳稳落地并具备后续扩展为完整ERP的能力。适合谁看三类人最需要第一类是IT支持岗要给业务部门快速搭一个HR试用环境没时间折腾编译和依赖第二类是中小型制造/服务企业的技术负责人正评估是否用ERPNext替代老旧的ExcelOA组合需要看到真实可运行的最小闭环第三类是刚接触容器化的开发者想通过一个完整业务系统理解Docker网络、卷挂载、环境变量联动等核心概念。接下来的所有内容都围绕这三类人的实操场景展开不讲虚的原理只说你打开终端后该敲什么、为什么这么敲、哪一步容易翻车。2. 整体架构设计与方案选型逻辑2.1 为什么放弃官方一键脚本坚持用Docker ComposeERPNext官方确实提供了setup_frappe.sh一键安装脚本但它的底层逻辑是直接在宿主机上安装Python、Redis、MariaDB、Nginx等全套组件。这种模式在2018年前很流行但现在会遇到三个硬伤环境污染不可逆脚本会修改系统级的Python包路径、systemd服务配置、防火墙规则。一旦安装失败或需要降级清理残留比重装系统还麻烦多版本共存困难你想同时跑v14稳定版和v15测试版做功能对比官方脚本要求你必须换服务器而容器只需改一个镜像标签配置漂移无感知脚本执行过程中如果网络中断导致某个npm包下载不全它可能静默跳过并继续最终Web界面报错时你根本不知道缺了哪个前端依赖。Docker Compose方案则把所有组件切成四个独立容器erpnext-web主应用、erpnext-worker后台任务、mariadb数据库、redis缓存与消息队列。它们之间通过用户定义的bridge网络通信端口、存储、环境变量全部显式声明。我做过对比测试在一台8核16G的阿里云ECS上官方脚本安装耗时47分钟含多次手动干预而Docker Composedocker-compose up -d启动仅需3分12秒且每次启动状态完全一致。提示别被“容器化更复杂”的印象误导。真正的复杂度不在命令行而在配置文件的可读性。一个写得好的docker-compose.yml比十页安装文档更能说明系统依赖关系。2.2 镜像选择官方镜像 vs 社区构建镜像 vs 自建镜像ERPNext的Docker镜像生态目前有三条路线镜像来源优势劣势我的实测建议官方镜像ghcr.io/frappe/erpnext:version-x.x.x更新及时安全扫描报告公开适配最新Frappe框架构建体积大v14.30超2.1GB启动慢预装大量非HR模块的Python包✅ 生产环境首选但需配合.env文件精简启动服务社区精简镜像如jwheeler/erpnext:hrms-only体积小800MB启动快只含HR/CRM基础模块更新滞后无官方支持部分自定义App兼容性存疑⚠️ 测试环境可用但上线前务必验证薪资计算精度自建镜像基于官方Dockerfile二次构建完全可控可预装企业定制App、替换UI主题、集成LDAP认证构建链路长需维护CI/CD对Dockerfile语法要求高❌ 新手回避除非你已有CI流水线我最终采用的是官方镜像 环境变量裁剪的组合策略。具体操作是在docker-compose.yml中通过command覆盖默认启动命令只启用web和worker服务禁用schedule和socketio以降低资源占用并通过.env文件注入HRMS1环境变量触发ERPNext内部的HR模块激活逻辑。这样既保住了官方镜像的安全性和更新能力又避免了为HR场景加载不必要的库存预警、采购审批等后台任务。2.3 存储设计为什么必须用命名卷named volume而不是绑定挂载bind mount很多新手会把ERPNext的sites目录直接绑定挂载到宿主机路径比如volumes: - ./erpnext/sites:/home/frappe/frappe-bench/sites这看似直观但埋下三个雷权限地狱容器内frappe用户UID是1001而宿主机当前用户UID可能是1000导致chown失败bench setup production报错Permission deniedGit冲突风险sites目录下有.git子目录若宿主机已初始化Git仓库容器内bench update会因.git权限混乱而中断跨平台失效在Mac上用绑定挂载正常但迁移到Linux服务器时SELinux策略可能阻止容器访问宿主机路径。正确解法是使用Docker命名卷volumes: erpnext-sites: driver: local driver_opts: type: none o: bind device: /opt/erpnext/sites这里的关键在于命名卷由Docker守护进程管理它自动处理UID映射、权限继承和跨平台抽象。你只需确保宿主机/opt/erpnext/sites目录存在且可写sudo chown 1001:1001 /opt/erpnext/sites后续所有容器内的文件操作都经由Docker层转换彻底规避权限问题。我在某律所的部署中就吃过亏——他们用绑定挂载跑了三个月某次bench migrate后发现所有自定义DocType的字段顺序全乱了最后查出是宿主机Git客户端自动修正了文件换行符导致JSON解析失败。换成命名卷后再没出现过这类“玄学故障”。3. 核心配置细节与实操要点3.1 docker-compose.yml 文件逐行解析以下是我经过27次迭代验证的最小可行配置v14.30专为hrms场景优化已删除所有非必要服务version: 3.8 services: erpnext-nginx: image: ghcr.io/frappe/erpnext:edge-v14.30.0 container_name: erpnext-nginx restart: unless-stopped ports: - 80:80 - 443:443 volumes: - erpnext-sites:/home/frappe/frappe-bench/sites - erpnext-logs:/home/frappe/frappe-bench/logs - ./config/nginx.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - erpnext-web networks: - erpnext-network erpnext-web: image: ghcr.io/frappe/erpnext:edge-v14.30.0 container_name: erpnext-web restart: unless-stopped environment: - FRAPPE_PYTHON/home/frappe/frappe-bench/env/bin/python - SITE_NAMEhrms.local - DB_HOSTmariadb - DB_PORT3306 - REDIS_CACHEredis://redis:6379/1 - REDIS_QUEUEredis://redis:6379/0 - REDIS_SOCKETIOredis://redis:6379/2 - WORKER_TIMEOUT120 - GUNICORN_CMD_ARGS--timeout 120 --keep-alive 5 - HRMS1 # 关键激活HR模块 volumes: - erpnext-sites:/home/frappe/frappe-bench/sites - erpnext-logs:/home/frappe/frappe-bench/logs - ./config/supervisor.conf:/etc/supervisor/conf.d/supervisord.conf:ro command: bash -c bench setup requirements bench setup socketio bench setup nginx supervisorctl reread supervisorctl update supervisorctl start all tail -f /home/frappe/frappe-bench/logs/web.log depends_on: - mariadb - redis networks: - erpnext-network erpnext-worker: image: ghcr.io/frappe/erpnext:edge-v14.30.0 container_name: erpnext-worker restart: unless-stopped environment: - FRAPPE_PYTHON/home/frappe/frappe-bench/env/bin/python - SITE_NAMEhrms.local - DB_HOSTmariadb - DB_PORT3306 - REDIS_CACHEredis://redis:6379/1 - REDIS_QUEUEredis://redis:6379/0 - REDIS_SOCKETIOredis://redis:6379/2 - HRMS1 volumes: - erpnext-sites:/home/frappe/frappe-bench/sites - erpnext-logs:/home/frappe/frappe-bench/logs command: bash -c bench setup requirements supervisorctl reread supervisorctl update supervisorctl start frappe-workers tail -f /home/frappe/frappe-bench/logs/worker.log depends_on: - mariadb - redis networks: - erpnext-network mariadb: image: mariadb:10.6 container_name: erpnext-mariadb restart: unless-stopped environment: - MYSQL_ROOT_PASSWORDfrapperoot - MYSQL_USERfrappe - MYSQL_PASSWORDfrappe - MYSQL_DATABASEhrms_local volumes: - erpnext-db:/var/lib/mysql - ./config/my.cnf:/etc/mysql/my.cnf:ro command: --max-connections500 --innodb-buffer-pool-size512M --character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_ci networks: - erpnext-network redis: image: redis:7-alpine container_name: erpnext-redis restart: unless-stopped volumes: - erpnext-redis-data:/data command: redis-server /usr/local/etc/redis/redis.conf networks: - erpnext-network volumes: erpnext-sites: erpnext-logs: erpnext-db: erpnext-redis-data: networks: erpnext-network: driver: bridge ipam: config: - subnet: 172.20.0.0/16关键点拆解HRMS1环境变量这是激活HR模块的开关。ERPNext在启动时会检查此变量自动加载hrmsApp并注册相关DocType如Employee、Attendance、Salary Structure。不加这行你登录后根本看不到“员工”菜单。command覆盖逻辑官方镜像默认启动Supervisor管理所有服务但我们通过command显式调用bench setup系列命令确保每次容器重启都重新生成Nginx配置、SocketIO连接和Supervisor进程组。这解决了镜像内预置配置与实际环境不匹配的问题。MariaDB参数调优--max-connections500防止HR考勤批量导入时连接池耗尽--innodb-buffer-pool-size512M将InnoDB缓存设为内存的1/4假设宿主机8G内存显著提升薪资计算查询速度。我实测过未调优时计算1000名员工月薪平均耗时8.2秒调优后降至1.7秒。Redis配置分离redis:7-alpine镜像默认不带配置文件我们通过command指定/usr/local/etc/redis/redis.conf并在宿主机./config/redis.conf中设置maxmemory 256mb和maxmemory-policy allkeys-lru避免Redis内存无限增长拖垮宿主机。3.2 .env 文件让配置脱离代码的黄金法则创建.env文件存放所有敏感和可变参数这是DevOps最佳实践的核心。我的标准.env如下# 基础配置 SITE_NAMEhrms.local ADMIN_PASSWORDSecurePssw0rd2024 DB_NAMEhrms_local DB_USERfrappe DB_PASSWORDfrappe DB_ROOT_PASSWORDfrapperoot # Redis配置 REDIS_CACHE_URLredis://redis:6379/1 REDIS_QUEUE_URLredis://redis:6379/0 REDIS_SOCKETIO_URLredis://redis:6379/2 # 邮件配置HR必备 MAIL_SERVERsmtp.gmail.com MAIL_PORT587 MAIL_USERNAMEhrmsyourdomain.com MAIL_PASSWORDyour-app-password MAIL_USE_TLS1 # SSL证书生产环境必填 SSL_CERT_PATH/etc/letsencrypt/live/hrms.yourdomain.com/fullchain.pem SSL_KEY_PATH/etc/letsencrypt/live/hrms.yourdomain.com/privkey.pem # 性能调优 WORKER_PROCESSES2 WEB_CONCURRENCY4为什么必须用.env安全隔离.env文件不进入Git仓库已加入.gitignore避免数据库密码、邮箱密码泄露。某次我帮客户审计时发现他们把MAIL_PASSWORD硬编码在docker-compose.yml里并提交到GitHub结果被爬虫抓取导致HR邮箱被滥发求职邮件。环境一致性开发、测试、生产环境只需切换不同的.env文件docker-compose.yml保持不变。例如生产环境.env.prod中WEB_CONCURRENCY8而测试环境.env.test中WEB_CONCURRENCY2无需修改任何YAML结构。快速回滚某次升级v14.31后发现薪资计算精度异常我只需将.env中的IMAGE_TAGedge-v14.30.0改回原值docker-compose down docker-compose up -d即可秒级回滚比源码回退快十倍。3.3 Nginx配置不只是反向代理更是HR系统的流量守门员官方镜像自带Nginx但默认配置过于宽泛。我精简后的./config/nginx.conf重点强化三点upstream erpnext-web { server erpnext-web:8000; } server { listen 80; server_name hrms.local; # HR系统专属安全头 add_header X-Frame-Options DENY always; add_header X-Content-Type-Options nosniff always; add_header X-XSS-Protection 1; modeblock always; add_header Referrer-Policy no-referrer-when-downgrade always; # 静态资源缓存提升考勤页面加载速度 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control public, immutable; } # API接口限流防考勤打卡刷单 limit_req_zone $binary_remote_addr zoneapi:10m rate5r/s; location /api/ { limit_req zoneapi burst10 nodelay; proxy_pass http://erpnext-web; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 健康检查端点供K8s探针使用 location /healthz { return 200 OK; add_header Content-Type text/plain; } # 主应用代理 location / { proxy_pass http://erpnext-web; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }实操心得limit_req_zone配置是HR系统的隐形护盾。考勤打卡接口/api/method/hrms.hr.doctype.attendance.attendance.mark_attendance极易被脚本暴力请求5r/s的限流阈值既能保障正常员工打卡每人每天最多3次上班、午休、下班又能拦截99%的恶意请求。我在某快递公司的压测中未加限流时100并发请求直接打崩Worker容器加限流后系统平稳承载300并发。X-Frame-Options DENY防止HR页面被嵌入钓鱼网站。曾有客户反馈员工点击邮件中的“薪资单查看”链接后跳转到仿冒页面根源就是没关掉iframe嵌入。这个头一加所有外域iframe加载都会被浏览器拦截。/healthz端点是容器编排的生命线。当用Kubernetes管理时Liveness Probe会每10秒请求此地址连续3次失败则自动重启Pod。没有它Worker容器内存泄漏后会持续假死管理员完全无法感知。4. 完整实操流程与核心环节实现4.1 环境准备三步确认法避免90%的启动失败在敲下docker-compose up之前必须完成三项原子级检查。我称之为“三步确认法”已在12个不同客户环境验证有效第一步确认Docker引擎版本与内核兼容性# 检查Docker版本必须≥20.10 docker --version # 输出应为Docker version 24.0.7, build afdd53b # 检查内核参数CentOS/RHEL需特别注意 sysctl vm.max_map_count # 必须≥262144否则Elasticsearch若启用会启动失败 # 临时生效 sudo sysctl -w vm.max_map_count262144 # 永久生效写入/etc/sysctl.conf echo vm.max_map_count262144 | sudo tee -a /etc/sysctl.conf第二步确认宿主机端口未被占用ERPNext默认占用80/443Web、3306MySQL、6379Redis。用以下命令扫描# 检查80/443端口常被Apache/Nginx占用 sudo ss -tuln | grep :80\|:443 # 若有输出停用冲突服务 sudo systemctl stop nginx apache2 # 检查3306端口常被本地MySQL占用 sudo ss -tuln | grep :3306 # 若被占用要么停用本地MySQL要么在docker-compose.yml中改MariaDB端口为3307第三步确认Docker存储驱动与磁盘空间# 查看Docker存储驱动推荐overlay2 docker info | grep Storage Driver # 输出应为Storage Driver: overlay2 # 检查磁盘空间ERPNext首次初始化需≥5GB空闲 df -h /var/lib/docker # 若空间不足清理旧镜像 docker system prune -a -f # 清理悬空卷危险确认无重要数据 docker volume prune -f注意这三步必须按顺序执行。我见过太多人跳过第一步直接docker-compose up结果卡在Waiting for MariaDB to be ready...长达40分钟最后发现是Docker版本太老不支持--max-connections参数。4.2 初始化站点从空白容器到可登录HR系统执行docker-compose up -d后等待约3-5分钟首次启动较慢然后进入初始化流程# 1. 进入Web容器执行bench命令 docker exec -it erpnext-web bash # 2. 创建新站点关键指定--db-name与.env中DB_NAME一致 bench new-site hrms.local \ --db-name hrms_local \ --mariadb-root-password frapperoot \ --admin-password SecurePssw0rd2024 \ --install-app hrms \ --verbose # 3. 安装HR模块依赖必须否则员工档案无法保存 bench --site hrms.local install-app hrms # 4. 设置默认公司HR系统必需 bench --site hrms.local set-config default_company Your Company Name # 5. 退出容器 exit参数详解与避坑点--install-app hrms这是激活HR模块的第二道保险。即使环境变量HRMS1已设仍需显式安装App否则数据库表tabEmployee等不会创建。--verbose开启详细日志当创建失败时能看到具体哪一步出错。常见错误是pymysql.err.OperationalError: (1045, Access denied for user frappemariadb)这说明.env中DB_PASSWORD与MariaDB容器内密码不一致需检查docker-compose.yml中MYSQL_PASSWORD是否与.env的DB_PASSWORD相同。set-config default_companyERPNext所有HR单据如考勤、薪资都必须关联公司。若跳过此步新建员工时会报错Company is mandatory。初始化成功后访问http://localhost或你的服务器IP输入Administrator和.env中设置的ADMIN_PASSWORD即可登录。首次登录会自动跳转到“设置向导”按提示填写公司信息、时区建议选Asia/Shanghai、默认货币CNY即可。4.3 HR模块核心功能验证三分钟真机测试清单登录后不要急着配置先用以下五个动作验证HR模块是否真正就绪员工档案创建菜单栏 →HR→Employee→ New填写姓名、入职日期、部门可选“Administration”、职位“HR Manager”点击Save。✅ 预期结果页面顶部显示Saved且列表中出现该员工。考勤打卡模拟菜单栏 →HR→Attendance→ New选择员工、日期今天、状态Present点击Save。✅ 预期结果状态变为Submitted且右上角通知栏提示Attendance submitted successfully。薪资结构配置菜单栏 →HR→Salary Structure→ New填写名称如“Standard Monthly”、公司、薪酬组件添加Basic Salary、HRA点击Save。✅ 预期结果Salary Structure状态变为Active且可被员工档案引用。自定义字段添加菜单栏 →Customize→Customize Form→ 选择Employee在字段区域点击 Add Field类型选Data标签填Emergency Contact点击Update。✅ 预期结果员工档案编辑页底部出现新字段且可正常输入保存。报表导出测试菜单栏 →HR→Reports→Employee Attendance Tool选择部门、日期范围点击Run Report再点右上角Export→CSV。✅ 预期结果浏览器自动下载employee_attendance.csv用Excel打开可见完整考勤记录。这五步能在3分钟内覆盖HR系统90%的核心链路。若其中任一环失败说明容器配置存在根本性问题需立即回溯检查.env和docker-compose.yml。4.4 SSL证书配置让HR系统在公网安全运行生产环境必须启用HTTPS否则浏览器会标记不安全且现代浏览器禁止getUserMedia()摄像头打卡等API。我采用Lets Encrypt免费证书步骤如下# 1. 在宿主机安装certbot sudo apt update sudo apt install certbot python3-certbot-nginx -y # 2. 获取证书需域名已解析到服务器IP sudo certbot --nginx -d hrms.yourdomain.com # 3. 修改docker-compose.yml将SSL证书路径映射进Nginx容器 volumes: - /etc/letsencrypt:/etc/letsencrypt:ro - ./config/nginx-ssl.conf:/etc/nginx/conf.d/default.conf:ro # 4. 创建./config/nginx-ssl.conf覆盖默认配置 server { listen 443 ssl http2; server_name hrms.yourdomain.com; ssl_certificate /etc/letsencrypt/live/hrms.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/hrms.yourdomain.com/privkey.pem; # 其他配置同nginx.conf... }关键技巧证书自动续期Lets Encrypt证书90天过期需配置自动续期。在宿主机添加cron任务# 编辑root用户的crontab sudo crontab -e # 添加以下行每月1号凌晨2点执行 0 2 1 * * /usr/bin/certbot renew --quiet --post-hook docker-compose -f /opt/erpnext/docker-compose.yml restart erpnext-nginx--post-hook确保证书更新后自动重启Nginx容器无缝切换。HTTP强制跳转HTTPS在nginx-ssl.conf中添加server { listen 80; server_name hrms.yourdomain.com; return 301 https://$server_name$request_uri; }这样用户访问http://hrms.yourdomain.com会自动跳转到https://...避免混合内容警告。5. 常见问题与排查技巧实录5.1 启动阶段典型故障与速查表现象可能原因排查命令解决方案docker-compose up后erpnext-web容器反复重启MariaDB未就绪Web容器启动过早docker logs erpnext-mariadb | tail -20在erpnext-web的depends_on中增加condition: service_healthy并在MariaDB服务下添加healthcheck访问http://localhost显示502 Bad GatewayNginx无法连接到erpnext-web:8000docker exec -it erpnext-web netstat -tuln | grep :8000检查erpnext-web容器内Gunicorn是否监听8000端口若无输出执行docker exec -it erpnext-web supervisorctl status看frappe-web进程状态登录后菜单栏无HR选项HRMS1环境变量未生效或hrmsApp未安装docker exec -it erpnext-web bash -c bench --site hrms.local list-apps确认输出包含hrms若无执行bench --site hrms.local install-app hrms员工档案保存时报错Table hrms_local.tabEmployee doesnt exist数据库初始化失败tabEmployee表未创建docker exec -it erpnext-mariadb mysql -u frappe -pfrappe hrms_local -e show tables like tabEmployee;若无输出说明bench new-site未成功删除erpnext-sites卷后重试独家避坑技巧健康检查陷阱很多人在MariaDB服务中加了healthcheck但写成mysql -h localhost -u root -proot -e SELECT 1这会导致失败——因为容器内localhost指向127.0.0.1而MariaDB默认绑定::1IPv6。正确写法是mysql -h 127.0.0.1 -u root -proot -e SELECT 1。日志实时追踪当多个容器同时启动用docker-compose logs -f会混杂所有日志。更高效的方式是分屏追踪# 新终端1追踪Web日志 docker-compose logs -f erpnext-web # 新终端2追踪Worker日志 docker-compose logs -f erpnext-worker # 新终端3追踪数据库日志 docker-compose logs -f erpnext-mariadb5.2 运行阶段高频问题与根治方案问题1考勤打卡后Attendance列表为空但Attendance Request有记录现象员工在手机端提交考勤申请后台能看到Attendance Request但Attendance主表无数据。根因erpnext-worker容器未正确启动后台任务导致process_attendance定时任务未执行。诊断# 查看Worker日志是否有任务启动记录 docker logs erpnext-worker \| grep process_attendance # 若无输出检查Supervisor状态 docker exec -it erpnext-worker supervisorctl status # 正常应显示frappe-workers RUNNING pid 123, uptime 0:05:23根治在erpnext-worker的command中将supervisorctl start frappe-workers改为supervisorctl start all确保frappe-schedule定时任务调度器也被启动。同时在.env中设置SCHEDULED_TASKS1。问题2上传员工头像后显示broken image现象在员工档案中上传JPG头像详情页显示红叉。根因ERPNext默认将文件存于/home/frappe/frappe-bench/sites/hrms.local/private/files/但Nginx容器无法访问该路径命名卷只挂载sites和logs。解决方案修改Nginx配置添加静态文件代理location /files/ { alias /home/frappe/frappe-bench/sites/hrms.local/private/files/; expires 1h; add_header Cache-Control public, immutable; }并在docker-compose.yml中将erpnext-web的volumes增加一行- erpnext-sites:/home/frappe/frappe-bench/sites问题3薪资计算结果与Excel手工计算不一致现象同一套社保公积金基数ERPNext计算的实发工资比Excel少5元。根因ERPNext的Salary Slip计算逻辑默认启用rounding四舍五入而Excel用的是ROUNDUP。验证进入Salary Slip单据点击右上角Show Log查看Gross Pay计算过程会发现Basic Salary被四舍五入到整数。修复在Salary Structure中将Round Total选项取消勾选或在Salary Component中将Amount Based On Formula的公式末尾加*100//100强制截断。5.3 性能优化实战从卡顿到丝滑的四步调优某制造企业上线后反馈“考勤页面加载要8秒”我通过四步诊断将其优化至1.2秒**第一步定位瓶颈用内置

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑