├── .codeclimate.yml ├── .gitignore ├── LICENSE ├── README.md ├── addons ├── buy │ ├── __init__.py │ ├── __openerp__.py │ ├── buy.py │ ├── buy_data.xml │ └── buy_view.xml ├── core │ ├── __init__.py │ ├── __openerp__.py │ ├── core.py │ └── core_view.xml ├── demo │ └── __init__.py ├── goods │ ├── __init__.py │ ├── __openerp__.py │ ├── action │ │ └── goods_action.xml │ ├── goods.py │ ├── menu │ │ └── goods_menu.xml │ └── view │ │ └── goods_view.xml ├── money │ ├── __init__.py │ ├── __openerp__.py │ ├── data │ │ ├── money_data.xml │ │ └── money_sequence.xml │ ├── money_order.py │ ├── money_transfer_order.py │ ├── other_money_order.py │ ├── report │ │ ├── __init__.py │ │ ├── bank_statements.py │ │ ├── bank_statements_view.xml │ │ ├── other_money_statements.py │ │ ├── other_money_statements_view.xml │ │ ├── partner_statements.py │ │ ├── partner_statements_view.xml │ │ ├── print.xml │ │ └── print_money_order.xml │ ├── view │ │ ├── money_order_view.xml │ │ ├── money_transfer_order_view.xml │ │ ├── other_money_order_view.xml │ │ └── reconcile_order_view.xml │ └── wizard │ │ ├── __init__.py │ │ ├── bank_statements_wizard.py │ │ ├── bank_statements_wizard_view.xml │ │ ├── other_money_statements_wizard.py │ │ ├── other_money_statements_wizard_view.xml │ │ ├── partner_statements_wizard.py │ │ └── partner_statements_wizard_view.xml ├── sell │ ├── __init__.py │ ├── __openerp__.py │ ├── sell.py │ ├── sell_data.xml │ └── sell_view.xml └── warehouse │ ├── __init__.py │ ├── __openerp__.py │ ├── action │ └── warehouse_action.xml │ ├── data │ ├── sequence.xml │ └── warehouse_data.xml │ ├── goods.py │ ├── html │ └── move_lot.html │ ├── inventory.py │ ├── menu │ └── warehouse_menu.xml │ ├── move_matching.py │ ├── production.py │ ├── report │ ├── __init__.py │ ├── lot_status.py │ ├── lot_status_view.xml │ ├── lot_track.py │ ├── lot_track_view.xml │ ├── report_base.py │ ├── stock_balance.py │ ├── stock_balance_view.xml │ ├── stock_transceive.py │ ├── stock_transceive_collect.py │ ├── stock_transceive_collect_view.xml │ └── stock_transceive_view.xml │ ├── static │ └── src │ │ ├── css │ │ └── style.css │ │ └── js │ │ └── warehouse_widget.js │ ├── utils.py │ ├── view │ ├── assets_backend.xml │ ├── goods_view.xml │ ├── inventory_view.xml │ ├── production_view.xml │ └── warehouse_view.xml │ ├── warehouse.py │ ├── warehouse_move.py │ ├── warehouse_move_line.py │ ├── warehouse_order.py │ └── wizard │ ├── __init__.py │ ├── lot_track_wizard.py │ ├── lot_track_wizard_view.xml │ ├── save_bom.py │ ├── save_bom_view.xml │ ├── stock_transceive_collect_wizard.py │ ├── stock_transceive_collect_wizard_view.xml │ ├── stock_transceive_wizard.py │ └── stock_transceive_wizard_view.xml └── extra ├── web_editable_list_length ├── __init__.py ├── __openerp__.py ├── static │ └── src │ │ └── js │ │ └── list.js └── views │ └── assets_backend.xml ├── web_editable_open_dialog ├── __init__.py ├── __openerp__.py ├── static │ └── src │ │ ├── css │ │ └── style.css │ │ └── js │ │ └── dialog.js └── views │ └── assets_backend.xml ├── web_float_limit ├── __init__.py ├── __openerp__.py ├── static │ └── src │ │ └── js │ │ └── limit.js └── views │ └── assets_backend.xml ├── web_menu_create ├── __init__.py ├── __openerp__.py ├── ir_ui_view.py ├── static │ └── src │ │ ├── css │ │ └── style.css │ │ └── js │ │ └── menu.js └── views │ └── assets_backend.xml ├── web_one2many_reconstruction ├── __init__.py ├── __openerp__.py ├── static │ └── src │ │ ├── css │ │ └── style.css │ │ ├── js │ │ └── one2many.js │ │ └── xml │ │ └── one2many.xml └── views │ └── assets_backend.xml ├── web_readonly_bypass ├── README.rst ├── __init__.py ├── __openerp__.py ├── static │ ├── src │ │ └── js │ │ │ └── readonly_bypass.js │ └── test │ │ └── web_readonly_bypass.js └── views │ └── readonly_bypass.xml └── web_sublist ├── __init__.py ├── __openerp__.py ├── static └── src │ ├── css │ └── style.css │ ├── js │ └── sublist.js │ └── xml │ └── sublist.xml └── views └── assets_backend.xml /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | csslint: 3 | enabled: true 4 | pep8: 5 | enabled: true 6 | eslint: 7 | enabled: true 8 | FIXME: 9 | enabled: true 10 | duplication: 11 | enabled: false 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | .idea 3 | .idea/* 4 | .project 5 | .pydevproject 6 | .settings/ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [在线试用](http://gooderp.osbzr.net/login?db=gooderp&login=admin&key=good) 2 | ====== 3 | 4 | [![Join the chat at https://gitter.im/osbzr/gooderp](https://badges.gitter.im/osbzr/gooderp.svg)](https://gitter.im/osbzr/gooderp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | [![Build Status](https://travis-ci.org/osbzr/gooderp.svg?branch=master)](https://travis-ci.org/osbzr/gooderp) 6 | [![Coverage Status](https://coveralls.io/repos/github/osbzr/gooderp/badge.svg?branch=master)](https://coveralls.io/github/osbzr/gooderp?branch=master) 7 | [![Issue Count](https://codeclimate.com/github/osbzr/gooderp/badges/issue_count.svg)](https://codeclimate.com/github/osbzr/gooderp) 8 | 9 | 开阖软件发起的开源ERP项目 10 | 11 | 如果你有一个苹果,我也有一个苹果,彼此交换后,你我还是一人一个苹果,但是如果你有一个想法,我有一个想法,彼此交换后,你我就都有两个想法,三个人呢?一百个人呢? 12 | 13 | 使用openobject框架 14 | 15 | 重写全部功能模块 16 | 17 | 18 | Why——为什么要做GOODERP 19 | --------------------- 20 | 1、OpenERP面向最终用户,GOODERP面向实施公司 21 | 22 | 2、OpenERP项目由openerp公司主导,GOODERP项目由实施公司主导 23 | 24 | 3、提高核心功能模块的稳定性和易用性,降低标准功能部署成本 25 | 26 | 4、针对现有成熟产品重新组织功能设计,使GOODERP有清晰的市场定位和竞争对手 27 | 28 | 5、实行开源项目贡献者奖励制度,让开源成为众包 29 | 30 | 6、参照现有ERP软件构建业务伙伴支持网络和实施工具包 31 | 32 | 7、通过大量读写代码培养和发现具备openobject平台二次开发能力的程序员 33 | 34 | 35 | What——关于GOODERP产品 36 | -------------------- 37 | 1、GOODERP是托管在github上的一个开源ERP项目 38 | 39 | 2、软件采用agpl协议,版权归代码提交者所有 40 | 41 | 3、项目范围是一组功能模块,包括财务加进销存的核心模块及满足行业特殊需求的模块 42 | 43 | 4、这些模块都以openobject8.0为平台开发 44 | 45 | 5、模块全部放在 osbzr/gooderp mater分支的根目录下,每个模块一个目录 46 | 47 | 6、参照 ys 的功能菜单和输出布局重新设计 48 | 49 | 7、项目本身不提供下载服务,上传下载均通过github版本管理工具 50 | 51 | 52 | Who——谁来做GOODERP项目 53 | --------------------- 54 | 1、项目经理:上海开阖软件有限公司 王剑峰 55 | 56 | 2、项目投资人:GOODERP认证业务伙伴 gooderp-partner 57 | 58 | 3、项目成员:任何人均可克隆、修改、提交合并请求 59 | 60 | 4、项目经理负责协调业务伙伴与贡献者关系 61 | 62 | 5、项目投资人负责审批分支合并请求,每月评定顶尖贡献者。 63 | 64 | 6、项目成员报告bug、通过提交分支合并请求的方式向项目贡献代码 65 | 66 | 67 | When——GOODERP项目的时间规划 68 | -------------------------- 69 | 1、项目启动日期2016年2月22日 70 | 71 | 2、第一阶段,2016年,完成财务+进销存+项目管理的核心功能 72 | 73 | 3、第二阶段,长期规划,根据客户项目和业务伙伴需求实现各行业纵深功能 74 | 75 | 4、每月定期(日期待定)举行业务伙伴会议,总结上月进度,评选最佳贡献者,计划下月工作 76 | 77 | 5、业务伙伴资格有效期为1年 78 | 79 | 6、项目实行7*24小时工作制,全年无休 80 | 81 | 7、项目以一个自然月为一个计划交付周期 82 | 83 | Where——使用github管理GOODERP开发 84 | ------------------------------- 85 | 86 | 1、快 87 | 88 | 2、程序员最爱 89 | 90 | 3、贡献代码方便 91 | 92 | 4、免费 93 | 94 | 5、不断优化 95 | 96 | 6、一站解决 97 | 98 | 7、在线沟通协作 99 | 100 | How——如何让GOODERP持续健康发展 101 | ----------------------------- 102 | 1、投资者应该参与决策 103 | 104 | 2、贡献者必须得到认可 105 | 106 | 3、现金回报及时到位 107 | 108 | 4、关注业务伙伴的需求,而非最终用户 109 | 110 | 5、搭建在线测试服务器 111 | 112 | 6、鼓励非程序员参与测试,特别是ys现有用户 113 | 114 | 7、开展多种双赢合作模式 115 | 116 | 开发环境准备 117 | ------------- 118 | 1.在github上fork点击右上角的fork 119 | 120 | 2.clone到本地 121 | 122 | git clone https://github.com/你的名字/gooderp.git 123 | 124 | 3.增加远程分支(也就是osbzr的分支)名为osbzr到你本地。 125 | 126 | git remote add osbzr https://github.com/osbzr/gooderp.git 127 | 128 | 环境就准备好了 129 | 130 | 131 | 把远程分支的合并到自己的分支 132 | ---------------------------- 133 | 1.把对方的代码拉到你本地。 134 | 135 | git fetch osbzr 136 | 137 | 2.合并对方代码 138 | 139 | git merge osbzr/master 140 | 141 | 3.最新的代码推送到你的github上。 142 | 143 | git push origin master 144 | 145 | 当本地代码写好要提交到主干项目 146 | ------------------------------- 147 | 1.添加要提交的目录 148 | 149 | git add . 150 | 151 | 2.提交更新 152 | 153 | git commit -m"本次修改的描述" 154 | 155 | 3.推送到github 156 | 157 | git push 158 | 159 | 4.在github上点击pull request按钮 160 | -------------------------------------------------------------------------------- /addons/buy/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import buy -------------------------------------------------------------------------------- /addons/buy/__openerp__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | { 3 | 'name': "GOODERP 采购模块", 4 | 'author': "flora@osbzr.com", 5 | 'website': "http://www.osbzr.com", 6 | 'category': 'gooderp', 7 | 'version': '8.0.0.1', 8 | 'depends': ['core','mail','warehouse','money'], 9 | 'data': [ 10 | 'buy_view.xml', 11 | 'buy_data.xml', 12 | ] 13 | } -------------------------------------------------------------------------------- /addons/buy/buy_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Buy Order 7 | buy.order 8 | 9 | 10 | Buy Order 11 | buy.order 12 | BO 13 | 5 14 | 15 | 16 | 17 | 18 | 19 | Buy Receipt 20 | buy.receipt 21 | 22 | 23 | Buy Receipt 24 | buy.receipt 25 | WH/IN/ 26 | 5 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /addons/core/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import core 3 | -------------------------------------------------------------------------------- /addons/core/__openerp__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | { 3 | 'name': "GOODERP 核心模块", 4 | 'author': "开阖软件", 5 | 'website': "http://www.osbzr.com", 6 | 'category': 'gooderp', 7 | 'version': '8.0.0.1', 8 | 'depends': [], 9 | 'data': [ 10 | 'core_view.xml', 11 | ] 12 | } -------------------------------------------------------------------------------- /addons/core/core.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from openerp import models, fields, api 4 | 5 | CORE_CATEGORY_TYPE = [('customer',u'客户'), 6 | ('supplier',u'供应商'), 7 | ('goods',u'商品'), 8 | ('expense',u'支出'), 9 | ('income',u'收入'), 10 | ('other_pay',u'其他支出'), 11 | ('other_get',u'其他收入'), 12 | ('attribute',u'属性'), 13 | ('goods',u'产品')] 14 | CORE_COST_METHOD = [('average',u'移动平均法'), 15 | ('fifo',u'先进先出法'), 16 | ] 17 | 18 | class core_value(models.Model): 19 | _name = 'core.value' 20 | name = fields.Char(u'名称') 21 | type = fields.Char(u'类型', default=lambda self: self._context.get('type')) 22 | 23 | class core_category(models.Model): 24 | _name = 'core.category' 25 | name = fields.Char(u'名称') 26 | type = fields.Selection(CORE_CATEGORY_TYPE,u'类型',default=lambda self: self._context.get('type')) 27 | 28 | class res_company(models.Model): 29 | _inherit = 'res.company' 30 | start_date = fields.Date(u'启用日期') 31 | quantity_digits = fields.Integer(u'数量小数位') 32 | amount_digits = fields.Integer(u'单价小数位') 33 | cost_method = fields.Selection(CORE_COST_METHOD,u'存货计价方法') 34 | negtive_quantity = fields.Boolean(u'是否检查负库存') 35 | draft_invoice = fields.Boolean(u'根据发票确认应收应付') 36 | 37 | class uom(models.Model): 38 | _name = 'uom' 39 | name = fields.Char(u'名称') 40 | 41 | class settle_mode(models.Model): 42 | _name = 'settle.mode' 43 | name = fields.Char(u'名称') 44 | 45 | class partner(models.Model): 46 | _name = 'partner' 47 | code = fields.Char(u'编号') 48 | name = fields.Char(u'名称') 49 | c_category_id = fields.Many2one('core.category',u'客户类别', 50 | domain=[('type','=','customer')],context={'type':'customer'}) 51 | s_category_id = fields.Many2one('core.category',u'供应商类别', 52 | domain=[('type','=','supplier')],context={'type':'supplier'}) 53 | receivable = fields.Float(u'应收余额') 54 | payable = fields.Float(u'应付余额') 55 | 56 | class goods(models.Model): 57 | _name = 'goods' 58 | code = fields.Char(u'编号') 59 | name = fields.Char(u'名称') 60 | category_id = fields.Many2one('core.category',u'产品类别', 61 | domain=[('type','=','goods')],context={'type':'goods'}) 62 | uom_id = fields.Many2one('uom',u'计量单位') 63 | uos_id = fields.Many2one('uom',u'辅助单位') 64 | conversion = fields.Float(u'转化率(1辅助单位等于多少计量单位)') 65 | cost = fields.Float(u'成本') 66 | price_ids = fields.One2many('goods.price','goods_id',u'价格清单') 67 | 68 | class goods_price(models.Model): 69 | _name = 'goods.price' 70 | goods_id = fields.Many2one('goods','商品') 71 | category_id = fields.Many2one('core.category',u'客户类别', 72 | domain=[('type','=','customer')],context={'type':'customer'}) 73 | price = fields.Float(u'价格') 74 | 75 | class warehouse(models.Model): 76 | _name = 'warehouse' 77 | name = fields.Char(u'名称') 78 | 79 | class staff(models.Model): 80 | _name = 'staff' 81 | name = fields.Char(u'名称') 82 | 83 | class bank_account(models.Model): 84 | _name = 'bank.account' 85 | name = fields.Char(u'名称') 86 | balance = fields.Float(u'余额') 87 | -------------------------------------------------------------------------------- /addons/demo/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /addons/goods/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import goods 3 | -------------------------------------------------------------------------------- /addons/goods/__openerp__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ############################################################################## 3 | # 4 | # OpenERP, Open Source Management Solution 5 | # Copyright (C) 2013-Today OpenERP SA (). 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Affero General Public License as 9 | # published by the Free Software Foundation, either version 3 of the 10 | # License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Affero General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Affero General Public License 18 | # along with this program. If not, see . 19 | # 20 | ############################################################################## 21 | 22 | { 23 | "name": "GOODERP Goods Management", 24 | "version": "0.1", 25 | "author": 'ZhengXiang', 26 | "website": "http://www.osbzr.com", 27 | "category": "Generic Modules", 28 | "depends": ['core', 'decimal_precision'], 29 | "description": """ 30 | """, 31 | "data": [ 32 | 'view/goods_view.xml', 33 | 'action/goods_action.xml', 34 | 'menu/goods_menu.xml', 35 | ], 36 | 'installable': True, 37 | "active": False, 38 | } 39 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: 40 | -------------------------------------------------------------------------------- /addons/goods/action/goods_action.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 产品 6 | goods 7 | tree,form 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /addons/goods/goods.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from openerp import models, fields, api 4 | 5 | 6 | class goods(models.Model): 7 | _inherit = 'goods' 8 | 9 | using_batch = fields.Boolean(u'批次管理') 10 | force_batch_one = fields.Boolean(u'每批次数量为1') 11 | attribute_ids = fields.One2many('attribute', 'goods_id', string=u'属性') 12 | 13 | 14 | class attribute(models.Model): 15 | _name = 'attribute' 16 | 17 | @api.one 18 | @api.depends('value_ids') 19 | def _compute_name(self): 20 | self.name = ' '.join([value.value_id.name for value in self.value_ids]) 21 | 22 | name = fields.Char(u'名称', compute='_compute_name', store=True,readonly=True) 23 | goods_id = fields.Many2one('goods', u'商品') 24 | value_ids = fields.One2many('attribute.value', 'attribute_id', string=u'属性') 25 | 26 | 27 | class attribute_value(models.Model): 28 | _name = 'attribute.value' 29 | _rec_name = 'value_id' 30 | attribute_id = fields.Many2one('attribute',u'属性') 31 | category_id = fields.Many2one('core.category',u'属性', 32 | domain=[('type','=','attribute')],context={'type':'attribute'} 33 | ,required='1') 34 | value_id = fields.Many2one('attribute.value.value',u'值', 35 | domain="[('category_id','=',category_id)]" 36 | ,required='1') 37 | class attribute_value(models.Model): 38 | _name = 'attribute.value.value' 39 | category_id = fields.Many2one('core.category',u'属性', 40 | domain=[('type','=','attribute')],context={'type':'attribute'} 41 | ,required='1') 42 | name = fields.Char(u'值') 43 | -------------------------------------------------------------------------------- /addons/goods/menu/goods_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /addons/goods/view/goods_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | goods.tree 6 | goods 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | goods.form 18 | goods 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
57 |
58 |
59 | 60 | attribute.form 61 | attribute 62 | 63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 |
73 |
74 |
75 |
-------------------------------------------------------------------------------- /addons/money/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import money_order 3 | import other_money_order 4 | import money_transfer_order 5 | import report 6 | import wizard -------------------------------------------------------------------------------- /addons/money/__openerp__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | { 3 | 'name': "GOODERP 会计模块", 4 | 'author': "judy@osbzr.com", 5 | 'website': "http://www.osbzr.com", 6 | 'category': 'gooderp', 7 | 'version': '8.0.0.1', 8 | 'depends': ['core','base'], 9 | 'data': [ 10 | 'view/money_order_view.xml', 11 | 'view/other_money_order_view.xml', 12 | 'view/money_transfer_order_view.xml', 13 | 'view/reconcile_order_view.xml', 14 | 'data/money_sequence.xml', 15 | 'data/money_data.xml', 16 | 'report/partner_statements_view.xml', 17 | 'wizard/partner_statements_wizard_view.xml', 18 | 'report/bank_statements_view.xml', 19 | 'wizard/bank_statements_wizard_view.xml', 20 | 'report/other_money_statements_view.xml', 21 | 'wizard/other_money_statements_wizard_view.xml', 22 | ] 23 | } -------------------------------------------------------------------------------- /addons/money/data/money_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 销售 7 | income 8 | 9 | 10 | 11 | 采购 12 | expense 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /addons/money/data/money_sequence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 收款单 7 | get.order 8 | 9 | 10 | 收款单 11 | get.order 12 | GET%(year)s 13 | 5 14 | 15 | 16 | 17 | 18 | 付款单 19 | pay.order 20 | 21 | 22 | 付款单 23 | pay.order 24 | PAY%(year)s 25 | 5 26 | 27 | 28 | 29 | 30 | 其他收入单 31 | other.get.order 32 | 33 | 34 | 其他收入单 35 | other.get.order 36 | OTHER_GET%(year)s 37 | 5 38 | 39 | 40 | 41 | 42 | 其他支出单 43 | other.pay.order 44 | 45 | 46 | 其他支出单 47 | other.pay.order 48 | OTHER_PAY%(year)s 49 | 5 50 | 51 | 52 | 53 | 54 | 资金转账单 55 | money.transfer.order 56 | 57 | 58 | 资金转账单 59 | money.transfer.order 60 | TR%(year)s 61 | 5 62 | 63 | 64 | 65 | 66 | 核销单 67 | reconcile.order 68 | 69 | 70 | 核销单 71 | reconcile.order 72 | RO%(year)s/ 73 | 5 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /addons/money/money_transfer_order.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ############################################################################## 3 | # 4 | # Copyright (C) 2016 开阖软件(). 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as 8 | # published by the Free Software Foundation, either version 3 of the 9 | # License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | # 19 | ############################################################################## 20 | 21 | from openerp.exceptions import except_orm 22 | from openerp import fields, models, api 23 | 24 | class money_transfer_order(models.Model): 25 | _name = 'money.transfer.order' 26 | _description = u'资金转账单' 27 | 28 | @api.model 29 | def create(self, values): 30 | print self._name 31 | if values.get('name', '/') == '/': 32 | values.update({'name': self.env['ir.sequence'].get(self._name) or '/'}) 33 | 34 | return super(money_transfer_order, self).create(values) 35 | 36 | state = fields.Selection([ 37 | ('draft', u'未审核'), 38 | ('done', u'已审核'), 39 | ], string=u'状态', readonly=True, default='draft', copy=False) 40 | name = fields.Char(string=u'单据编号', copy=False, default='/') 41 | date = fields.Date(string=u'单据日期', default=lambda self: fields.Date.context_today(self), readonly=True, states={'draft': [('readonly', False)]}) 42 | note = fields.Text(string=u'备注', readonly=True, states={'draft': [('readonly', False)]}) 43 | line_ids = fields.One2many('money.transfer.order.line', 'transfer_id', string=u'资金转账单行', readonly=True, states={'draft': [('readonly', False)]}) 44 | 45 | @api.multi 46 | def money_transfer_done(self): 47 | '''转账单的审核按钮''' 48 | for transfer in self: 49 | if not transfer.line_ids: 50 | raise except_orm('错误','请先输入转账金额') 51 | if transfer.line_ids.out_bank_id == transfer.line_ids.in_bank_id: 52 | raise except_orm('错误','转出账户与转入账户不能相同') 53 | for line in transfer.line_ids: 54 | if line.amount < 0: 55 | raise except_orm('错误','转账金额必须大于0') 56 | if line.out_bank_id.balance < line.amount: 57 | raise except_orm('错误','转出账户余额不足') 58 | else: 59 | line.out_bank_id.balance -= line.amount 60 | line.in_bank_id.balance += line.amount 61 | transfer.state = 'done' 62 | return True 63 | 64 | @api.multi 65 | def money_transfer_draft(self): 66 | '''转账单的反审核按钮''' 67 | for transfer in self: 68 | for line in transfer.line_ids: 69 | if line.in_bank_id.balance < line.amount: 70 | raise except_orm('错误','转入账户余额不足') 71 | else: 72 | line.in_bank_id.balance -= line.amount 73 | line.out_bank_id.balance += line.amount 74 | transfer.state = 'draft' 75 | return True 76 | 77 | class money_transfer_order_line(models.Model): 78 | _name = 'money.transfer.order.line' 79 | _description = u'资金转账单明细' 80 | 81 | transfer_id = fields.Many2one('money.transfer.order', string=u'资金转账单') 82 | out_bank_id = fields.Many2one('bank.account', string=u'转出账户', required=True) 83 | in_bank_id = fields.Many2one('bank.account', string=u'转入账户', required=True) 84 | amount = fields.Float(string=u'金额') 85 | mode_id = fields.Many2one('settle.mode', string=u'结算方式') 86 | number = fields.Char(string=u'结算号') 87 | note = fields.Char(string=u'备注') -------------------------------------------------------------------------------- /addons/money/other_money_order.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ############################################################################## 3 | # 4 | # Copyright (C) 2016 开阖软件(). 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as 8 | # published by the Free Software Foundation, either version 3 of the 9 | # License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | # 19 | ############################################################################## 20 | 21 | from openerp.exceptions import except_orm 22 | from openerp import fields, models, api 23 | 24 | class other_money_order(models.Model): 25 | _name = 'other.money.order' 26 | _description = u'其他收入/其他支出' 27 | 28 | TYPE_SELECTION = [ 29 | ('other_pay', u'其他收入'), 30 | ('other_get', u'其他支出'), 31 | ] 32 | 33 | @api.model 34 | def create(self, values): 35 | # 创建单据时,更新订单类型的不同,生成不同的单据编号 36 | if self._context.get('type') == 'other_get': 37 | values.update({'name': self.env['ir.sequence'].get('other.get.order') or '/'}) 38 | if self._context.get('type') == 'other_pay' or values.get('name', '/') == '/': 39 | values.update({'name': self.env['ir.sequence'].get('other.pay.order') or '/'}) 40 | 41 | return super(other_money_order, self).create(values) 42 | 43 | @api.one 44 | @api.depends('line_ids.amount') 45 | def _compute_total_amount(self): 46 | # 计算应付金额/应收金额 47 | self.total_amount = sum(line.amount for line in self.line_ids) 48 | 49 | state = fields.Selection([ 50 | ('draft', u'未审核'), 51 | ('done', u'已审核'), 52 | ], string=u'状态', readonly=True, default='draft', copy=False) 53 | partner_id = fields.Many2one('partner', string=u'往来单位', readonly=True, states={'draft': [('readonly', False)]}) 54 | date = fields.Date(string=u'单据日期', default=lambda self: fields.Date.context_today(self), readonly=True, states={'draft': [('readonly', False)]}) 55 | name = fields.Char(string=u'单据编号', copy=False, readonly=True, default='/') 56 | total_amount = fields.Float(string=u'金额', compute='_compute_total_amount', store=True, readonly=True) 57 | bank_id = fields.Many2one('bank.account', string=u'结算账户',required=True, readonly=True, states={'draft': [('readonly', False)]}) 58 | line_ids = fields.One2many('other.money.order.line', 'other_money_id', string=u'收支单行', readonly=True, states={'draft': [('readonly', False)]}) 59 | type = fields.Selection(TYPE_SELECTION, string=u'类型', default=lambda self: self._context.get('type'), readonly=True, states={'draft': [('readonly', False)]}) 60 | 61 | @api.onchange('partner_id') 62 | def _onchange_partner(self): 63 | ''' 64 | 根据所选业务伙伴源单填充行 65 | ''' 66 | self.line_ids = [] 67 | lines = [] 68 | for invoice in self.env['money.invoice'].search([('partner_id','=',self.partner_id.id),('to_reconcile','>',0)]): 69 | lines.append((0,0,{ 70 | 'category_id':invoice.category_id.id, 71 | 'source_id':invoice.id, 72 | 'amount':invoice.to_reconcile, 73 | })) 74 | self.line_ids = lines 75 | 76 | @api.multi 77 | def other_money_done(self): 78 | '''其他收支单的审核按钮''' 79 | for other in self: 80 | if other.total_amount <= 0: 81 | raise except_orm(u'错误', u'金额应该大于0') 82 | for line in other.line_ids: 83 | # 针对源单付款,则更新源单和供应商应付 84 | if line.source_id: 85 | if line.amount > line.source_id.to_reconcile: 86 | raise except_orm(u'错误', u'核销金额大于源单未核销金额') 87 | else: 88 | line.source_id.to_reconcile -= line.amount 89 | other.partner_id.payable -= line.amount 90 | # 根据单据类型更新账户余额 91 | if other.type == 'other_pay': 92 | other.bank_id.balance -= other.total_amount 93 | else: 94 | other.bank_id.balance += other.total_amount 95 | other.state = 'done' 96 | return True 97 | 98 | @api.multi 99 | def other_money_draft(self): 100 | '''其他收支单的反审核按钮''' 101 | for other in self: 102 | for line in other.line_ids: 103 | # 针对源单付款,则更新源单和供应商应付 104 | if line.source_id: 105 | line.source_id.to_reconcile += line.amount 106 | other.partner_id.payable += line.amount 107 | # 根据单据类型更新账户余额 108 | if other.type == 'other_pay': 109 | other.bank_id.balance += other.total_amount 110 | else: 111 | other.bank_id.balance -= other.total_amount 112 | other.state = 'draft' 113 | return True 114 | 115 | @api.multi 116 | def print_other_money_order(self): 117 | '''打印 其他收入/支出单''' 118 | assert len(self._ids) == 1, '一次执行只能有一个id' 119 | return self.env['report'].get_action('money.report_other_money_order') 120 | 121 | class other_money_order_line(models.Model): 122 | _name = 'other.money.order.line' 123 | _description = u'其他收支单明细' 124 | 125 | other_money_id = fields.Many2one('other.money.order', string=u'其他收支') 126 | category_id = fields.Many2one('core.category', u'类别', domain="[('type', '=', context.get('type'))]") 127 | source_id = fields.Many2one('money.invoice', string=u'源单') 128 | amount = fields.Float(string=u'金额') 129 | note = fields.Char(string=u'备注') 130 | -------------------------------------------------------------------------------- /addons/money/report/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import partner_statements 3 | import bank_statements 4 | import other_money_statements -------------------------------------------------------------------------------- /addons/money/report/bank_statements.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from openerp import fields, models, api, tools 3 | 4 | class bank_statements_report(models.Model): 5 | _name = "bank.statements.report" 6 | _description = u"现金银行报表" 7 | _auto = False 8 | _order = 'date' 9 | 10 | @api.one 11 | @api.depends('get', 'pay', 'bank_id') 12 | def _compute_balance(self): 13 | # 相邻的两条记录,bank_id不同,重新计算账户余额 14 | pre_record = self.search([('id', '=', self.id - 1), ('bank_id', '=', self.bank_id.id)]) 15 | if pre_record: 16 | before_balance = pre_record.balance 17 | else: 18 | before_balance = 0 19 | self.balance += before_balance + self.get - self.pay 20 | 21 | bank_id = fields.Many2one('bank.account', string=u'账户名称', readonly=True) 22 | date = fields.Date(string=u'日期', readonly=True) 23 | name = fields.Char(string=u'单据编号', readonly=True) 24 | get = fields.Float(string=u'收入', readonly=True) 25 | pay = fields.Float(string=u'支出', readonly=True) 26 | balance = fields.Float(string=u'账户余额', compute='_compute_balance', readonly=True) 27 | partner_id = fields.Many2one('partner', string=u'往来单位', readonly=True) 28 | note = fields.Char(string=u'备注', readonly=True) 29 | 30 | def init(self, cr): 31 | # union money_order, other_money_order, money_transfer_order 32 | tools.drop_view_if_exists(cr, 'bank_statements_report') 33 | cr.execute(""" 34 | CREATE or REPLACE VIEW bank_statements_report AS ( 35 | SELECT ROW_NUMBER() OVER(ORDER BY bank_id,date) AS id, 36 | bank_id, 37 | date, 38 | name, 39 | get, 40 | pay, 41 | balance, 42 | partner_id, 43 | note 44 | FROM 45 | (SELECT mol.bank_id, 46 | mo.date, 47 | mo.name, 48 | (CASE WHEN mo.type = 'get' THEN mol.amount ELSE 0 END) AS get, 49 | (CASE WHEN mo.type = 'pay' THEN mol.amount ELSE 0 END) AS pay, 50 | 0 AS balance, 51 | mo.partner_id, 52 | mol.note 53 | FROM money_order_line AS mol 54 | LEFT JOIN money_order AS mo ON mol.money_id = mo.id 55 | UNION ALL 56 | SELECT omo.bank_id, 57 | omo.date, 58 | omo.name, 59 | (CASE WHEN omo.type = 'other_get' THEN omo.total_amount ELSE 0 END) AS get, 60 | (CASE WHEN omo.type = 'other_pay' THEN omo.total_amount ELSE 0 END) AS pay, 61 | 0 AS balance, 62 | omo.partner_id, 63 | NULL AS note 64 | FROM other_money_order AS omo 65 | UNION ALL 66 | SELECT mtol.out_bank_id AS bank_id, 67 | mto.date, 68 | mto.name, 69 | 0 AS get, 70 | mtol.amount AS pay, 71 | 0 AS balance, 72 | NULL AS partner_id, 73 | mto.note 74 | FROM money_transfer_order_line AS mtol 75 | LEFT JOIN money_transfer_order AS mto ON mtol.transfer_id = mto.id 76 | UNION ALL 77 | SELECT mtol.in_bank_id AS bank_id, 78 | mto.date, 79 | mto.name, 80 | mtol.amount AS get, 81 | 0 AS pay, 82 | 0 AS balance, 83 | NULL AS partner_id, 84 | mto.note 85 | FROM money_transfer_order_line AS mtol 86 | LEFT JOIN money_transfer_order AS mto ON mtol.transfer_id = mto.id 87 | ) AS bs) 88 | """) 89 | 90 | @api.multi 91 | def find_source_order(self): 92 | # 查看源单,三种情况:收付款单、其他收支单、资金转换单 93 | money = self.env['money.order'].search([('name', '=', self.name)]) 94 | other_money = self.env['other.money.order'].search([('name', '=', self.name)]) 95 | 96 | if money: 97 | view = self.env.ref('money.money_order_form') 98 | return { 99 | 'name': u'收付款单', 100 | 'view_type': 'form', 101 | 'view_mode': 'form', 102 | 'view_id': False, 103 | 'views': [(view.id, 'form')], 104 | 'res_model': 'money.order', 105 | 'type': 'ir.actions.act_window', 106 | 'res_id': money.id 107 | } 108 | elif other_money: 109 | view = self.env.ref('money.other_money_order_form') 110 | return { 111 | 'name': u'其他收支单', 112 | 'view_type': 'form', 113 | 'view_mode': 'form', 114 | 'view_id': False, 115 | 'views': [(view.id, 'form')], 116 | 'res_model': 'other.money.order', 117 | 'type': 'ir.actions.act_window', 118 | 'res_id': other_money.id, 119 | 'context': {'type': False} 120 | } 121 | 122 | transfer_order = self.env['money.transfer.order'].search([('name', '=', self.name)]) 123 | view = self.env.ref('money.money_transfer_order_form') 124 | 125 | return { 126 | 'name': u'资金转换单', 127 | 'view_type': 'form', 128 | 'view_mode': 'form', 129 | 'view_id': False, 130 | 'views': [(view.id, 'form')], 131 | 'res_model': 'money.transfer.order', 132 | 'type': 'ir.actions.act_window', 133 | 'res_id': transfer_order.id 134 | } 135 | 136 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: 137 | -------------------------------------------------------------------------------- /addons/money/report/bank_statements_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | bank.statements.report.tree 7 | bank.statements.report 8 | 9 | 10 | 11 | 12 |