├── wizard ├── __init__.py ├── update_fields.xml └── import_wizard.py ├── .gitignore ├── __init__.py ├── models ├── payment.py ├── invoice.py ├── __init__.py ├── export_exception.py ├── import_exception.py ├── package.py ├── stock.py ├── category.py ├── tax.py ├── test.php ├── procurement.py ├── job.py ├── delivery.py ├── mapping.py ├── mage_api.py ├── country.py ├── defaults.py ├── create_mage_order.py ├── attribute.py ├── partner.py ├── mage.py └── product.py ├── jobs ├── __init__.py ├── shipworks.py ├── price.py ├── .sale.py.swp ├── users.py ├── category.py ├── mass_inventory.py ├── invoice.py ├── fix_shipments.py ├── grouped_relation.py ├── links.py ├── partner.py ├── create_product.py ├── backup_package ├── stock.py ├── metadata.py ├── attribute.py ├── product.py ├── package.py └── update_status.py ├── security └── mage2odoo_groups.xml ├── data └── mage_shipping.xml ├── views ├── product_category.xml ├── amazon.xml ├── stock.xml ├── model.xml ├── misc.xml ├── delivery.xml ├── import_exception.xml ├── export_exception.xml ├── import_export.xml ├── jobs.xml ├── core.xml ├── mapping.xml ├── product.xml ├── partner.xml ├── sites.xml ├── attribute.xml └── sale.xml ├── __openerp__.py └── README.md /wizard/__init__.py: -------------------------------------------------------------------------------- 1 | import import_wizard 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.save 3 | *.tmp 4 | *.DS_Store 5 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | import models 2 | import wizard 3 | import jobs 4 | -------------------------------------------------------------------------------- /models/payment.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | 3 | 4 | class PaymentMethod(osv.osv): 5 | _inherit = 'payment.method' 6 | _columns = { 7 | 'mage_code': fields.char('Magento Code', select=True), 8 | 9 | } 10 | -------------------------------------------------------------------------------- /models/invoice.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | 3 | class AccountInvoice(osv.osv): 4 | _inherit = 'account.invoice' 5 | _columns = { 6 | 'mage_export_error': fields.boolean('Magento Export Error', copy=False), 7 | 'external_id': fields.integer('Magento Invoice ID', copy=False, select=True), 8 | } 9 | -------------------------------------------------------------------------------- /jobs/__init__.py: -------------------------------------------------------------------------------- 1 | import attribute 2 | import metadata 3 | import product 4 | import category 5 | import sale 6 | import invoice 7 | import package 8 | import partner 9 | import links 10 | import grouped_relation 11 | import users 12 | import update_status 13 | import stock 14 | import create_product 15 | import fix_shipments 16 | import mass_inventory 17 | import shipworks 18 | -------------------------------------------------------------------------------- /security/mage2odoo_groups.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mage2odoo Manager 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- 1 | import datamapper 2 | import attribute 3 | import product 4 | import mage 5 | import job 6 | import mapping 7 | import mage_api 8 | import category 9 | import sale 10 | import partner 11 | import country 12 | import payment 13 | import delivery 14 | import tax 15 | import invoice 16 | import stock 17 | import procurement 18 | import package 19 | import create_mage_order 20 | import import_exception 21 | import export_exception 22 | -------------------------------------------------------------------------------- /data/mage_shipping.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Magento Shipping 7 | mage_shipping 8 | service 9 | 0.00 10 | False 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /models/export_exception.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | 3 | 4 | class MageExportException(osv.osv): 5 | _name = 'mage.export.exception' 6 | _columns = { 7 | 'name': fields.char('Name'), 8 | 'type': fields.char('Type'), 9 | 'external_id': fields.char('External Id'), 10 | 'message': fields.text('Message'), 11 | 'data': fields.text('Data'), 12 | 'job': fields.many2one('mage.job', 'Job'), 13 | } 14 | 15 | def retry_job_object(self, cr, uid, ids): 16 | return True 17 | 18 | -------------------------------------------------------------------------------- /models/import_exception.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | 3 | 4 | class MageImportException(osv.osv): 5 | _name = 'mage.import.exception' 6 | _rec_name = 'external_id' 7 | _columns = { 8 | 'type': fields.char('Type'), 9 | 'external_id': fields.char('External Id'), 10 | 'message': fields.text('Message'), 11 | 'data': fields.text('Data'), 12 | 'job': fields.many2one('mage.job', 'Job'), 13 | } 14 | 15 | def retry_job_object(self, cr, uid, ids): 16 | return True 17 | 18 | -------------------------------------------------------------------------------- /wizard/update_fields.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Make Invoices 6 | ir.actions.act_window 7 | sale.make.invoice 8 | form 9 | form 10 | 11 | new 12 | True 13 | 14 | -------------------------------------------------------------------------------- /views/product_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mage Product Category Form 5 | product.category 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | --> 19 | 20 | 21 | -------------------------------------------------------------------------------- /views/amazon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Amazon Orders 5 | ir.actions.act_window 6 | sale.order 7 | form 8 | tree,form,calendar,graph 9 | [('amazon_process', '=', True)] 10 | 11 | {} 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /jobs/shipworks.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | from pprint import pprint as pp 3 | import pytz 4 | from datetime import datetime, timedelta 5 | 6 | class MageJob(osv.osv): 7 | _inherit = 'mage.job' 8 | 9 | 10 | def reset_shipworks_orders(self, cr, uid, job, context=None): 11 | now = datetime.utcnow() 12 | central = pytz.timezone('US/Central') 13 | utc = pytz.timezone('UTC') 14 | utc_now = utc.localize(now) 15 | # final_value = utc_now.astimezone(central) - timedelta(hour$ 16 | final_value = utc_now.astimezone(central) 17 | stamp = final_value.strftime('%Y-%m-%d') 18 | query = "UPDATE stock_picking SET sw_exp = False, sw_pre_exp = False WHERE write_date > '%s' OR create_date > '%s'" % (stamp, stamp) 19 | cr.execute(query) 20 | return True 21 | -------------------------------------------------------------------------------- /models/package.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | 3 | 4 | class StockOutPackage(osv.osv): 5 | _inherit = 'stock.out.package' 6 | _columns = { 7 | 'sale': fields.many2one('sale.order', select=True), 8 | 'mage_package_state': fields.selection([('pending', 'Pending'), 9 | ('exception', 'Exception'), 10 | ('done', 'Done') 11 | ], 'Mage Package State', select=True), 12 | } 13 | 14 | _defaults = { 15 | 'mage_package_state': 'pending', 16 | } 17 | 18 | 19 | def create(self, cr, uid, data, context=None): 20 | if data.get('picking'): 21 | picking = self.pool.get('stock.picking').browse(cr, uid, data['picking']) 22 | if picking.sale: 23 | data['sale'] = picking.sale.id 24 | 25 | return super(StockOutPackage, self).create(cr, uid, data, context=context) 26 | -------------------------------------------------------------------------------- /models/stock.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | 3 | class StockPicking(osv.osv): 4 | _inherit = 'stock.picking' 5 | _columns = { 6 | 'mage_export_error': fields.boolean('Magento Export Error', copy=False), 7 | 'external_id': fields.integer('Magento Shipment ID', copy=False, select=True), 8 | 'sale': fields.many2one('sale.order', 'Sale Order', select=True), 9 | 'shipping_state': fields.related('partner_id', 'state_id', type='many2one', relation='res.country.state', string='Shipping State'), 10 | 'shipping_city': fields.related('partner_id', 'city', type='char', string='Shipping City'), 11 | 'mage_store': fields.related('sale', 'mage_store', type='many2one', relation='mage.store.view', string='Magento Store'), 12 | } 13 | 14 | 15 | 16 | class StockMove(osv.osv): 17 | _inherit = 'stock.move' 18 | _order = 'date desc' 19 | -------------------------------------------------------------------------------- /jobs/price.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | from pprint import pprint as pp 3 | from datetime import datetime 4 | from tzlocal import get_localzone 5 | 6 | class product_product(osv.osv): 7 | _inherit = 'product.product' 8 | _columns = { 9 | 'tmp_price': fields.float('Temp Price'), 10 | } 11 | 12 | class MageIntegrator(osv.osv_memory): 13 | 14 | _inherit = 'mage.integrator' 15 | 16 | def update_product_cost(self, cr, uid, job, context=None): 17 | 18 | product_obj = self.pool.get('product.product') 19 | product_ids = product_obj.search(cr, uid, []) 20 | for product in product_obj.browse(cr, uid, product_ids): 21 | price = product.standard_price 22 | product_obj.write(cr, uid, product.id, {'tmp_price': price}) 23 | print 'Updated Price' 24 | 25 | 26 | cr.execute("UPDATE sale_order_line line SET purchase_price = product.tmp_price FROM product_product product WHERE product.id = line.product_id") 27 | cr.commit() 28 | -------------------------------------------------------------------------------- /views/stock.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mage Stock Picking Form 6 | stock.picking 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /models/category.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | 3 | 4 | class ProductCategory(osv.osv): 5 | _inherit = 'product.category' 6 | _columns = { 7 | 'external_id': fields.integer('External Id', select=True, copy=False), 8 | 'position': fields.integer('Position'), 9 | 'mage_active': fields.boolean('Mage Active'), 10 | } 11 | 12 | 13 | def get_or_create_odoo_record(self, cr, uid, job, external_id): 14 | category_id = self.get_mage_record(cr, uid, external_id) 15 | if not category_id: 16 | category_id = self.get_and_create_mage_record(cr, uid, job, 'catalog_category.info', external_id) 17 | 18 | return self.browse(cr, uid, category_id) 19 | 20 | 21 | def prepare_odoo_record_vals(self, cr, uid, job, record): 22 | return { 23 | 'name': record['name'], 24 | 'parent_id': self.get_mage_record(cr, uid, record['parent_id']), 25 | 'external_id': record['category_id'], 26 | 27 | } 28 | -------------------------------------------------------------------------------- /jobs/.sale.py.swp: -------------------------------------------------------------------------------- 1 | b0nano 2.5.3!Irootubuntusale.py -------------------------------------------------------------------------------- /jobs/users.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | from pprint import pprint as pp 3 | from datetime import datetime 4 | from tzlocal import get_localzone 5 | 6 | class MageIntegrator(osv.osv_memory): 7 | 8 | _inherit = 'mage.integrator' 9 | 10 | def sync_admin_users(self, cr, uid, job, context=None): 11 | user_obj = self.pool.get('res.users') 12 | records = self._get_job_data(cr, uid, job, 'oo_websites.users', []) 13 | pp(records) 14 | for record in records: 15 | vals = self.prepare_user_vals(cr, uid, record) 16 | user_ids = user_obj.search(cr, uid, [('login', '=', record['email'])]) 17 | if user_ids: 18 | user_obj.write(cr, uid, user_ids[0], vals) 19 | print 'Updated User with ID: %s' % vals['external_id'] 20 | else: 21 | user_obj.create(cr, uid, vals) 22 | print 'Created User in Odoo with ID: %s' % vals['external_id'] 23 | 24 | return True 25 | 26 | 27 | def prepare_user_vals(self, cr, uid, record): 28 | vals = { 29 | 'login': record['email'], 30 | 'name': ' '.join([record['firstname'], record['lastname']]), 31 | 'external_id': record['user_id'] 32 | } 33 | 34 | return vals 35 | -------------------------------------------------------------------------------- /views/model.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mage Model Tree 6 | ir.model 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Model Mapping 19 | ir.model 20 | ir.actions.act_window 21 | form 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /__openerp__.py: -------------------------------------------------------------------------------- 1 | { 2 | 'name': 'Mage2Odoo', 3 | 'version': '1.1', 4 | 'author': 'Kyle Waid', 5 | 'category': 'Sales Management', 6 | 'depends': ['payment_method', 'delivery', 'stock_package', 'product_sku_upc', 'sale_stock', 'asin_label'], 7 | 'website': 'https://www.gcotech.com', 8 | 'description': """ 9 | """, 10 | 'data': ['security/mage2odoo_groups.xml', 11 | 'views/core.xml', 12 | 'views/attribute.xml', 13 | 'views/sites.xml', 14 | 'views/mapping.xml', 15 | 'views/jobs.xml', 16 | 'views/product.xml', 17 | 'views/import_export.xml', 18 | 'views/product_category.xml', 19 | 'views/model.xml', 20 | 'views/misc.xml', 21 | 'views/sale.xml', 22 | 'views/stock.xml', 23 | 'views/delivery.xml', 24 | 'views/partner.xml', 25 | 'views/import_exception.xml', 26 | 'views/export_exception.xml', 27 | 'views/exception.xml', 28 | 'views/amazon.xml', 29 | 'data/mage_shipping.xml', 30 | ], 31 | 'test': [ 32 | ], 33 | 'installable': True, 34 | 'auto_install': False, 35 | 'external_dependencies': { 36 | 'python': ['magento', 'pycountry'], 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /wizard/import_wizard.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | from openerp.tools.translate import _ 3 | import cStringIO 4 | import csv 5 | import base64 6 | 7 | 8 | class MageImportWizard(osv.osv_memory): 9 | _name = 'mage.import.wizard' 10 | _columns = { 11 | 'file': fields.binary('Input File'), 12 | 'file_name': fields.char('File Name', size=64), 13 | } 14 | 15 | 16 | def import_products(self, cr, uid, ids, context=None): 17 | wizard = self.browse(cr, uid, ids[0], context=context) 18 | file = wizard.file 19 | data = base64.decodestring(file) 20 | input = cStringIO.StringIO(data) 21 | reader = csv.DictReader(input, quotechar='"', delimiter=',') 22 | product_obj = self.pool.get('product.product') 23 | error_count = 0 24 | columns = [ 25 | 'SKU', 26 | 'NAME', 27 | 'ATTRIBUTE_SET_ID', 28 | 'STORE_ID', 29 | 'TAX_CLASS_ID', 30 | 'DESCRIPTION', 31 | 'PRODUCT_TYPE', 32 | 'CATEGORY_IDS', 33 | 'WEBSITE_IDS', 34 | 'WEIGHT', 35 | 'PRICE' 36 | ] 37 | for row in reader: 38 | prepare_product_vals 39 | 40 | return True 41 | 42 | 43 | class MageExportWizard(osv.osv_memory): 44 | _name = 'mage.export.wizard' 45 | -------------------------------------------------------------------------------- /jobs/category.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import osv, fields 2 | from pprint import pprint as pp 3 | 4 | class MageIntegrator(osv.osv_memory): 5 | 6 | _inherit = 'mage.integrator' 7 | 8 | def import_categories(self, cr, uid, job, context=None): 9 | categories = self._get_job_data(cr, uid, job, 'catalog_category.tree', []) 10 | cat_obj = self.pool.get('product.category') 11 | mappinglines = self._get_mappinglines(cr, uid, job.mapping.id) 12 | vals = cat_obj.prepare_odoo_record_vals(cr, uid, job, categories) 13 | # vals = self._transform_record(cr, uid, job, categories, 'from_mage_to_odoo', mappinglines) 14 | del vals['parent_id'] 15 | result = cat_obj.upsert_mage_record(cr, uid, vals) 16 | print result 17 | self.process_category_tree(cr, uid, job, mappinglines, categories['children']) 18 | 19 | return True 20 | 21 | 22 | def process_category_tree(self, cr, uid, job, mappinglines, categories, context=None): 23 | cat_obj = self.pool.get('product.category') 24 | for category in categories: 25 | vals = cat_obj.prepare_odoo_record_vals(cr, uid, job, category) 26 | result = cat_obj.upsert_mage_record(cr, uid, vals) 27 | print result 28 | if category['children']: 29 | self.process_category_tree(cr, uid, job, mappinglines, category['children']) 30 | 31 | return True 32 | 33 | -------------------------------------------------------------------------------- /views/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mage Order Status Mapping Tree 6 | mage.mapping.order.state 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Status Mappings 20 | mage.mapping.order.state 21 | ir.actions.act_window 22 | form 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /views/delivery.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mage Delivery Carrier Tree 6 | delivery.carrier 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Mage Delivery Carrier Form 18 | delivery.carrier 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /models/tax.py: -------------------------------------------------------------------------------- 1 | """ 2 | account 3 | 4 | Account 5 | 6 | :copyright: (c) 2013 by Openlabs Technologies & Consulting (P) Limited 7 | :license: AGPLv3, see LICENSE for more details. 8 | """ 9 | from openerp.osv import osv, fields 10 | 11 | 12 | class AccountTax(osv.Model): 13 | "Account Tax" 14 | _inherit = 'account.tax' 15 | 16 | _columns = { 17 | 'mage_tax': fields.boolean('Is this tax used on magento ?', copy=False), 18 | 'apply_on_magento_shipping': fields.boolean( 19 | 'Is this tax applied on magento shipping ?', 20 | help='This tax should have *Tax Included in Price* set as True', copy=False 21 | ) 22 | } 23 | 24 | def check_apply_on_magento_shipping(self, cursor, user, ids, context=None): 25 | """ 26 | Checks that only one tax has been chosen to be applied on magento 27 | shipping 28 | 29 | :param cursor: Database cursor 30 | :param user: ID of current user 31 | :param ids: IDs of records 32 | :param context: Application context 33 | :return: True or False 34 | """ 35 | if len(self.search(cursor, user, [ 36 | ('apply_on_magento_shipping', '=', True) 37 | ], context=context)) > 1: 38 | return False 39 | return True 40 | 41 | _constraints = [ 42 | ( 43 | check_apply_on_magento_shipping, 44 | 'Error: Only 1 tax can be chosen to apply on magento shipping', 45 | [] 46 | ) 47 | ] 48 | 49 | def onchange_apply_on_magento_shipping( 50 | self, cursor, user, ids, apply_on_magento_shipping, context=None 51 | ): 52 | """Set *Tax Included in Price* set as True 53 | """ 54 | return {'value': {'price_include': apply_on_magento_shipping}} 55 | -------------------------------------------------------------------------------- /views/import_exception.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mage Import Exceptions Search 5 | mage.import.exception 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 25 | 26 | 27 | Mage Import Exceptions Tree 28 | mage.import.exception 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Import Exceptions 41 | ir.actions.act_window 42 | mage.import.exception 43 | form 44 | {} 45 | 46 | tree,form 47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /jobs/mass_inventory.py: -------------------------------------------------------------------------------- 1 | from openerp.osv import fields, osv, orm 2 | import openerp.addons.decimal_precision as dp 3 | from openerp.tools.translate import _ 4 | from openerp import tools 5 | 6 | class MageJob(osv.osv): 7 | _inherit = "mage.job" 8 | 9 | def zero_all_negative(self, cr, uid, job, context=None): 10 | if context is None: 11 | context = {} 12 | 13 | location = 12 14 | location_name = 'Stock' 15 | 16 | inventory_obj = self.pool.get('stock.inventory') 17 | inventory_line_obj = self.pool.get('stock.inventory.line') 18 | product_obj = self.pool.get('product.product') 19 | 20 | filter = 'partial' 21 | inventory_id = inventory_obj.create(cr, uid, { 22 | 'name': 'Zero Inventory For Location: %s' % location_name, 23 | 'filter': filter, 24 | 'location_id': location, 25 | }, context=context) 26 | 27 | product_ids = product_obj.search(cr, uid, []) 28 | ok = False 29 | for product in product_obj.browse(cr, uid, product_ids, context={'location_id': location, 'location': location}): 30 | product_qty_available = product.qty_available 31 | if product_qty_available < 0: 32 | ok = True 33 | print 'SKU: %s' % product.default_code 34 | print 'Quantity Available: %s' % product.qty_available 35 | 36 | product = product.with_context(location=location, lot_id=False) 37 | th_qty = product.qty_available 38 | line_data = { 39 | 'inventory_id': inventory_id, 40 | 'product_qty': 0, 41 | 'location_id': location, 42 | 'product_id': product.id, 43 | 'product_uom_id': product.uom_id.id, 44 | 'theoretical_qty': th_qty, 45 | 'prod_lot_id': False 46 | } 47 | inventory_line_obj.create(cr , uid, line_data, context=context) 48 | 49 | # if ok: 50 | # inventory_obj.action_done(cr, uid, [inventory_id], context=context) 51 | return True 52 | -------------------------------------------------------------------------------- /views/export_exception.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mage Export Exceptions Search 5 | mage.export.exception 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 25 | 26 | 27 | Mage export Exceptions Tree 28 | mage.export.exception 29 | 30 | 31 | 32 | 33 | 34 |