1
# -*- coding: utf-8 -*-
2
##############################################################################
4
# OpenERP, Open Source Management Solution
5
# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
6
# Author: Yannick Gouin <yannick.gouin@elico-corp.com>
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU Affero General Public License as
10
# published by the Free Software Foundation, either version 3 of the
11
# License, or (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU Affero General Public License for more details.
18
# You should have received a copy of the GNU Affero General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21
##############################################################################
23
from osv import osv, fields
24
from datetime import datetime
25
from dateutil.relativedelta import relativedelta
27
from openerp import netsvc
28
from openerp.tools.translate import _
31
class sale_order(osv.osv):
32
_inherit = "sale.order"
34
def _get_dts_id(self, cr, uid, ids, fields, args, context=None):
36
for so in self.browse(cr, uid, ids, context=context):
37
result[so.id] = so.pts_id and so.pts_id.dts_id and so.pts_id.dts_id.id or False
40
def _so_to_update_after_dts_change(self, cr, uid, ids, fields=None, arg=None, context=None):
41
if type(ids) != type([]):
43
return self.pool.get('sale.order').search(cr, uid, [('pts_id', 'in', ids)]) or []
46
'sale.order': (lambda self, cr, uid, ids, context: ids, ['pts_id'], 10),
47
'delivery.time': (_so_to_update_after_dts_change, ['dts_id'], 10),
51
'pts_id': fields.many2one('delivery.time', 'Preparation Time', domain=[('type', '=', 'pts')]),
52
'dts_id': fields.function(_get_dts_id, method=True, type='many2one', relation='delivery.time', string='Delivery Time', store=_store_dts_id, readonly=True, domain=[('type', '=', 'dts')]),
53
'batch_id': fields.many2one('picking.batch', 'Picking Batch', change_default=True),
54
'start_date': fields.datetime('Delivery Start Date'),
55
'end_date': fields.datetime(' Delivery End Date'),
56
# 'so_payment_method': fields.char('Payment Method', size=32),
60
def action_cancel_order_with_moves_not_delivered(self, cr, uid, ids, context=None):
61
wf_service = netsvc.LocalService("workflow")
64
sale_order_line_obj = self.pool.get('sale.order.line')
65
drl_obj = self.pool.get('delivery.route.line')
66
#proc_obj = self.pool.get('procurement.order')
67
for sale in self.browse(cr, uid, ids, context=context):
69
for pick in sale.picking_ids:
70
for mov in pick.move_lines:
71
if mov.state not in ('done','cancel'):
72
mov.write({'state':'cancel'})
74
for pick in sale.picking_ids:
75
if pick.state != 'cancel':
76
#wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_cancel', cr)
77
pick.write({'state':'cancel'})
78
for inv in sale.invoice_ids:
79
wf_service.trg_validate(uid, 'account.invoice', inv.id, 'invoice_cancel', cr)
80
for line in sale.order_line:
81
if line.procurement_id:
82
wf_service.trg_validate(uid, 'procurement.order', line.procurement_id.id, 'button_check', cr)
84
#cancel delivery route line
85
drl_ids = drl_obj.search(cr, uid, [('sale_order_id','=',sale.id),('state','!=','cancel')])
86
drl_obj.action_cancel(cr,uid,drl_ids,context=context)
88
order_ref = context.get('order_ref',False)
89
self.write(cr, uid, [sale.id], {'state':'shipping_except','client_order_ref':order_ref})
92
_logger.info('==== #LY action_cancel_order_with_moves_not_delivered fail %s===='%(sale.id))
95
def action_cancel_order_with_moves(self, cr, uid, ids, context=None):
96
wf_service = netsvc.LocalService("workflow")
99
sale_order_line_obj = self.pool.get('sale.order.line')
100
drl_obj = self.pool.get('delivery.route.line')
101
#proc_obj = self.pool.get('procurement.order')
102
for sale in self.browse(cr, uid, ids, context=context):
104
if sale.state == 'done':
106
for pick in sale.picking_ids:
107
if pick.state == 'done':
109
for mov in pick.move_lines:
110
if mov.state == 'done':
112
for inv in sale.invoice_ids:
113
if inv.state == 'paid':
116
for pick in sale.picking_ids:
117
wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_cancel', cr)
118
for pick in sale.picking_ids:
119
if pick.state != 'cancel':
120
wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_cancel', cr)
122
for inv in sale.invoice_ids:
123
wf_service.trg_validate(uid, 'account.invoice', inv.id, 'invoice_cancel', cr)
124
for line in sale.order_line:
125
if line.procurement_id:
126
wf_service.trg_validate(uid, 'procurement.order', line.procurement_id.id, 'button_check', cr)
128
#cancel delivery route line
129
drl_ids = drl_obj.search(cr, uid, [('sale_order_id','=',sale.id),('state','!=','cancel')])
130
drl_obj.action_cancel(cr,uid,drl_ids,context=context)
132
sale_order_line_obj.write(cr, uid, [l.id for l in sale.order_line], {'state': 'cancel'})
133
self.write(cr, uid, [sale.id], {'state': 'cancel'})
136
_logger.info('==== #LY action_cancel_order_with_moves fail %s===='%(sale.id))
139
def _prepare_order_line_procurement(self, cr, uid, order, pt_id, line, move_id, date_planned, context=None):
142
'origin': order.name,
143
'date_planned': date_planned,
144
'product_id': line.product_id.id,
145
'product_qty': line.product_uom_qty,
146
'product_uom': line.product_uom.id,
147
'product_uos_qty': (line.product_uos and line.product_uos_qty) or line.product_uom_qty,
148
'product_uos': (line.product_uos and line.product_uos.id) or line.product_uom.id,
149
'location_id': order.shop_id.warehouse_id.lot_stock_id.id,
150
'procure_method': line.type,
152
'company_id': order.company_id.id,
157
def _prepare_order_line_move_fc(self, cr, uid, order, line, picking_id, pt_id, date_planned, context=None):
158
location_id = order.shop_id.warehouse_id.lot_stock_id.id
159
output_id = order.shop_id.warehouse_id.lot_output_id.id
162
'picking_id': picking_id,
163
'product_id': line.product_id.id,
164
'date': date_planned,
165
'date_expected': date_planned,
166
'product_qty': line.product_uom_qty,
167
'product_uom': line.product_uom.id,
168
'product_uos_qty': (line.product_uos and line.product_uos_qty) or line.product_uom_qty,
169
'product_uos': (line.product_uos and line.product_uos.id) or line.product_uom.id,
170
'product_packaging': line.product_packaging.id,
171
'partner_id': line.address_allotment_id.id or order.partner_shipping_id.id,
172
'location_id': location_id,
173
'location_dest_id': output_id,
174
'sale_line_id': line.id,
175
'tracking_id': False,
177
'company_id': order.company_id.id,
178
'price_unit': line.product_id.standard_price or 0.0,
182
def _prepare_order_picking(self, cr, uid, order, dt_id, pt_id, context=None):
183
# SHOULD USE ir_sequence.next_by_code() or ir_sequence.next_by_id()
184
pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out')
187
'origin': order.name,
188
'date': order.date_order,
191
'move_type': order.picking_policy,
193
'partner_id': order.partner_shipping_id.id,
195
'invoice_state': (order.order_policy == 'picking' and '2binvoiced') or 'none',
196
'company_id': order.company_id.id,
201
def _prepare_pts_dts(self, cr, uid, order, context=None):
204
tz = pytz.timezone('Asia/Shanghai')
205
tz2 = pytz.timezone('America/Anchorage')
206
delivery_time_obj = self.pool.get('delivery.time')
207
time_slot_obj = self.pool.get('delivery.time.slot')
217
address = order.partner_shipping_id or order.partner_id or False
220
min_date = order.start_date
221
dts = order.start_date
222
dts = datetime.strptime(dts, '%Y-%m-%d %H:%M:%S')
223
dts = pytz.utc.localize(dts).astimezone(tz)
225
pts = datetime.strptime(order.date_order, '%Y-%m-%d')
226
pts = pytz.utc.localize(pts).astimezone(tz)
231
start_date = datetime.strftime(dts, '%Y-%m-%d')
232
from_time = datetime.strftime(dts, '%H:%M')
233
#LY remove the shanghai restrict out
234
# if address and (not address.city or address.city.lower() in ['shanghai']):
235
# from_time = datetime.strftime(dts, '%H:%M')
236
# else: # eg: in Nanjing
237
# from_time = '09:30'
238
name = datetime.strftime(dts, '%y%m%d')
240
start_date_pts = start_date
242
slot_ids = time_slot_obj.search(cr, uid, [('max_time', '>=', from_time), ('type', '=', 'dts')], order='max_time')
244
slot = time_slot_obj.browse(cr, uid, slot_ids[0])
246
end_date = start_date + ' ' + slot.end_time
247
start_date += ' ' + slot.start_time
248
start_date = datetime.strptime(start_date, '%Y-%m-%d %H:%M')
249
start_date = pytz.utc.localize(start_date).astimezone(tz2)
250
start_date = datetime.strftime(start_date, '%Y-%m-%d %H:%M')
251
end_date = datetime.strptime(end_date, '%Y-%m-%d %H:%M')
252
end_date = pytz.utc.localize(end_date).astimezone(tz2)
253
end_date = datetime.strftime(end_date, '%Y-%m-%d %H:%M')
255
dt_ids = delivery_time_obj.search(cr, uid, [('name', '=', name), ('type', '=', 'dts'), ('slot_id', '=', slot.id)])
259
dt_id = delivery_time_obj.create(cr, uid, {
261
'start_date': start_date,
262
'end_date': end_date,
270
date_pts = datetime.strftime(pts, '%Y-%m-%d')
271
from_time = datetime.strftime(pts, '%H:%M')
272
if date_pts < datetime.strftime(dts, '%Y-%m-%d'):
273
date_pts = datetime.strftime(dts, '%Y-%m-%d')
276
pts_slot_ids = time_slot_obj.search(cr, uid, [('max_time', '>=', from_time), ('type', '=', 'pts'), ('dts_id', '=', slot.id)], order='max_time')
278
pts_slot = time_slot_obj.browse(cr, uid, pts_slot_ids[0])
279
name_pts += pts_slot.name
280
end_date_pts = start_date_pts + ' ' + pts_slot.end_time
281
start_date_pts += ' ' + pts_slot.start_time
282
start_date_pts = datetime.strptime(start_date_pts, '%Y-%m-%d %H:%M')
283
start_date_pts = pytz.utc.localize(start_date_pts).astimezone(tz2)
284
start_date_pts = datetime.strftime(start_date_pts, '%Y-%m-%d %H:%M')
285
end_date_pts = datetime.strptime(end_date_pts, '%Y-%m-%d %H:%M')
286
end_date_pts = pytz.utc.localize(end_date_pts).astimezone(tz2)
287
end_date_pts = datetime.strftime(end_date_pts, '%Y-%m-%d %H:%M')
289
pt_ids = delivery_time_obj.search(cr, uid, [('name', '=', name_pts), ('type', '=', 'pts'), ('slot_id', '=', pts_slot.id)])
293
pt_id = delivery_time_obj.create(cr, uid, {
295
'start_date': start_date_pts,
296
'end_date': end_date_pts,
299
'slot_id': pts_slot.id,
303
val['pts_id'] = pt_id
306
return min_date, dt_id, pt_id
309
def _create_pickings_and_procurements(self, cr, uid, order, order_lines, picking_id=False, context=None):
310
"""Create the required procurements to supply sales order lines, also connecting
311
the procurements to appropriate stock moves in order to bring the goods to the
312
sales order's requested location.
314
If ``picking_id`` is provided, the stock moves will be added to it, otherwise
315
a standard outgoing picking will be created to wrap the stock moves, as returned
316
by :meth:`~._prepare_order_picking`.
318
Modules that wish to customize the procurements or partition the stock moves over
319
multiple stock pickings may override this method and call ``super()`` with
320
different subsets of ``order_lines`` and/or preset ``picking_id`` values.
322
:param browse_record order: sales order to which the order lines belong
323
:param list(browse_record) order_lines: sales order line records to procure
324
:param int picking_id: optional ID of a stock picking to which the created stock moves
325
will be added. A new picking will be created if ommitted.
329
move_obj = self.pool.get('stock.move')
330
picking_obj = self.pool.get('stock.picking')
331
procurement_obj = self.pool.get('procurement.order')
334
min_date, dt_id, pt_id = self._prepare_pts_dts(cr, uid, order)
335
# min_date, dt_id, pt_id = order.date_order, order.dts_id.id, order.pts_id.id
336
print '<<<<<<<<<<<<<< %s, %s, %s' % (min_date, dt_id, pt_id)
338
for line in order_lines:
339
if line.state == 'done':
342
date_planned = min_date or self._get_date_planned(cr, uid, order, line, order.date_order, context=context)
345
if line.product_id.type in ('product', 'consu'):
347
picking_id = picking_obj.create(cr, uid, self._prepare_order_picking(cr, uid, order, dt_id, pt_id, context=context))
348
move_id = move_obj.create(cr, uid, self._prepare_order_line_move_fc(cr, uid, order, line, picking_id, pt_id, date_planned, context=context))
350
# a service has no stock move
353
proc_id = procurement_obj.create(cr, uid, self._prepare_order_line_procurement(cr, uid, order, pt_id, line, move_id, date_planned, context=context))
354
proc_ids.append(proc_id)
355
line.write({'procurement_id': proc_id})
356
self.ship_recreate(cr, uid, order, line, move_id, proc_id)
358
wf_service = netsvc.LocalService("workflow")
360
wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
361
for proc_id in proc_ids:
362
wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
364
if order.state == 'shipping_except':
365
val['state'] = 'progress'
366
val['shipped'] = False
368
if (order.order_policy == 'manual'):
369
for line in order.order_line:
370
if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
371
val['state'] = 'manual'
379
class picking_batch(osv.osv):
380
_name = "picking.batch"
382
'name': fields.char('Name', size=32, translate=True),
383
'picking_ids': fields.one2many('stock.picking', 'batch_id', 'Contains'),
384
'active': fields.boolean('Active'),
394
class stock_picking(osv.osv):
395
_name = "stock.picking"
396
_inherit = "stock.picking"
398
'batch_id': fields.many2one('picking.batch', 'Picking Batch', change_default=True),
399
'route_line_id': fields.one2many('delivery.route.line', 'picking_id', 'Delivery Time'),
400
'so_payment_method': fields.char('Payment Method', size=32),
403
def write(self, cr, uid, ids, vals, context=None):
404
context = context or {}
406
if type(ids) != type([]):
409
move_pool = self.pool.get('stock.move')
410
proc_pool = self.pool.get('procurement.order')
411
pts_pool = self.pool.get('delivery.time')
412
drl_pool = self.pool.get('delivery.route.line')
414
if 'pts_id' not in vals:
415
pts_id = pts_pool.search(cr, uid, [('active', '=', True), ('type', '=', 'pts'), ('dts_id', '=', vals['dts_id'])], order='start_date DESC')
418
vals.update({'pts_id':pts_id})
420
pts_id = vals['pts_id']
423
move_ids = move_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('picking_id', 'in', ids)])
425
move_pool.write(cr, uid, move_ids, {'pts_id':pts_id})
426
proc_ids = proc_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('move_id', 'in', move_ids)])
428
proc_pool.write(cr, uid, proc_ids, {'pts_id':pts_id})
430
# Actually DONE in fields.function
431
# route_lines = drl_pool.search(cr, uid, [('state', 'in', ['draft']), ('picking_id', 'in', ids)])
433
# drl_pool.write(cr, uid, route_lines, {'dts_id': vals['dts_id']})
434
return super(stock_picking, self).write(cr, uid, ids, vals, context=context)
437
def pts_id_change(self, cr, uid, ids, pts_id, context=None):
439
context = context or {}
440
if type(ids) != type([]):
442
move_pool = self.pool.get('stock.move')
443
proc_pool = self.pool.get('procurement.order')
444
pts_pool = self.pool.get('delivery.time')
445
drl_pool = self.pool.get('delivery.route.line')
448
pts = pts_pool.browse(cr, uid, [pts_id])[0]
449
#self.write(cr, uid, ids, {'dts_id':pts and pts.dts_id and pts.dts_id.id or False})
450
res['dts_id'] = pts and pts.dts_id and pts.dts_id.id or False
452
move_ids = move_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('picking_id', 'in', ids)])
454
vals = {'pts_id':pts_id}
456
vals.update({'date_expected':pts.dts_id.start_date})
457
move_pool.write(cr, uid, move_ids, vals)
458
proc_ids = proc_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('move_id', 'in', move_ids)])
460
proc_pool.write(cr, uid, proc_ids, {'pts_id':pts_id})
462
# Actually DONE in fields.function
463
# route_lines = drl_pool.search(cr, uid, [('state', 'in', ['draft']), ('picking_id', 'in', ids)])
464
# if route_lines and 'dts_id' in res:
465
# drl_pool.write(cr, uid, route_lines, {'dts_id': res['dts_id']})
466
return {'value': res}
469
def create(self, cr, uid, data, context=None):
473
if not data.get('pts_id', False) and data.get('origin', False):
474
so_obj = self.pool.get('sale.order')
475
so_ids = so_obj.search(cr, uid, [('name', '=', data.get('origin'))]) or []
476
for so in so_obj.browse(cr, uid, so_ids):
477
data.update({'pts_id':so.pts_id and so.pts_id.id or False, 'dts_id':so.pts_id and so.pts_id.dts_id and so.pts_id.dts_id.id or False})
479
return_type = data.get('return', 'none')
480
sp = super(stock_picking, self).create(cr, uid, data, context=context)
481
if data.get('type', 'internal') in ['in','out'] and data.get('pts_id', False) and return_type not in ['customer', 'supplier']:
482
self.pool.get('delivery.route.line').create(cr, uid, {'picking_id':sp, })
488
class stock_picking_out(osv.osv):
489
_inherit = "stock.picking.out"
491
'batch_id': fields.many2one('picking.batch', 'Picking Batch', change_default=True),
492
'route_line_id': fields.one2many('delivery.route.line', 'picking_id', 'Delivery Time'),
493
'so_payment_method': fields.char('Payment Method', size=32),
496
def write(self, cr, uid, ids, vals, context=None):
497
context = context or {}
499
if type(ids) != type([]):
502
move_pool = self.pool.get('stock.move')
503
proc_pool = self.pool.get('procurement.order')
504
pts_pool = self.pool.get('delivery.time')
505
drl_pool = self.pool.get('delivery.route.line')
507
if 'pts_id' not in vals:
508
pts_id = pts_pool.search(cr, uid, [('active', '=', True), ('type', '=', 'pts'), ('dts_id', '=', vals['dts_id'])], order='start_date DESC')
511
vals.update({'pts_id':pts_id})
513
pts_id = vals['pts_id']
516
move_ids = move_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('picking_id', 'in', ids)])
518
move_pool.write(cr, uid, move_ids, {'pts_id':pts_id})
519
proc_ids = proc_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('move_id', 'in', move_ids)])
521
proc_pool.write(cr, uid, proc_ids, {'pts_id':pts_id})
523
# Actually DONE in fields.function
524
# route_lines = drl_pool.search(cr, uid, [('state', 'in', ['draft']), ('picking_id', 'in', ids)])
526
# drl_pool.write(cr, uid, route_lines, {'dts_id': vals['dts_id']})
527
return super(stock_picking_out, self).write(cr, uid, ids, vals, context=context)
530
def pts_id_change(self, cr, uid, ids, pts_id, context=None):
532
context = context or {}
533
if type(ids) != type([]):
535
move_pool = self.pool.get('stock.move')
536
proc_pool = self.pool.get('procurement.order')
537
pts_pool = self.pool.get('delivery.time')
538
drl_pool = self.pool.get('delivery.route.line')
541
pts = pts_pool.browse(cr, uid, [pts_id])[0]
542
#self.write(cr, uid, ids, {'dts_id':pts and pts.dts_id and pts.dts_id.id or False})
543
res['dts_id'] = pts and pts.dts_id and pts.dts_id.id or False
545
move_ids = move_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('picking_id', 'in', ids)])
547
vals = {'pts_id':pts_id}
549
vals.update({'date_expected':pts.dts_id.start_date})
550
move_pool.write(cr, uid, move_ids, vals)
551
proc_ids = proc_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('move_id', 'in', move_ids)])
553
proc_pool.write(cr, uid, proc_ids, {'pts_id':pts_id})
555
# Actually DONE in fields.function
556
# route_lines = drl_pool.search(cr, uid, [('state', 'in', ['draft']), ('picking_id', 'in', ids)])
557
# if route_lines and 'dts_id' in res:
558
# drl_pool.write(cr, uid, route_lines, {'dts_id': res['dts_id']})
559
return {'value': res}
562
def create(self, cr, uid, data, context=None):
566
if not data.get('pts_id', False) and data.get('origin', False):
567
so_obj = self.pool.get('sale.order')
568
so_ids = so_obj.search(cr, uid, [('name', '=', data.get('origin'))]) or []
569
for so in so_obj.browse(cr, uid, so_ids):
570
data.update({'pts_id':so.pts_id and so.pts_id.id or False, 'dts_id':so.pts_id and so.pts_id.dts_id and so.pts_id.dts_id.id or False})
572
return_type = data.get('return', 'none')
573
sp = super(stock_picking_out, self).create(cr, uid, data, context=context)
574
if data.get('pts_id', False) and return_type not in ['customer', 'supplier']:
575
self.pool.get('delivery.route.line').create(cr, uid, {'picking_id':sp, })
581
class stock_picking_in(osv.osv):
582
_inherit = "stock.picking.in"
585
'batch_id': fields.many2one('picking.batch', 'Picking Batch', change_default=True),
586
'route_line_id': fields.one2many('delivery.route.line', 'picking_id', 'Delivery Time'),
589
def write(self, cr, uid, ids, vals, context=None):
590
context = context or {}
592
if type(ids) != type([]):
595
move_pool = self.pool.get('stock.move')
596
proc_pool = self.pool.get('procurement.order')
597
pts_pool = self.pool.get('delivery.time')
598
drl_pool = self.pool.get('delivery.route.line')
600
if 'pts_id' not in vals:
601
pts_id = pts_pool.search(cr, uid, [('active', '=', True), ('type', '=', 'pts'), ('dts_id', '=', vals['dts_id'])], order='start_date DESC')
604
vals.update({'pts_id':pts_id})
606
pts_id = vals['pts_id']
609
move_ids = move_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('picking_id', 'in', ids)])
611
move_pool.write(cr, uid, move_ids, {'pts_id':pts_id})
612
proc_ids = proc_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('move_id', 'in', move_ids)])
614
proc_pool.write(cr, uid, proc_ids, {'pts_id':pts_id})
616
# Actually DONE in fields.function
617
# route_lines = drl_pool.search(cr, uid, [('state', 'in', ['draft']), ('picking_id', 'in', ids)])
619
# drl_pool.write(cr, uid, route_lines, {'dts_id': vals['dts_id']})
620
return super(stock_picking_in, self).write(cr, uid, ids, vals, context=context)
623
def pts_id_change(self, cr, uid, ids, pts_id, context=None):
625
context = context or {}
626
if type(ids) != type([]):
628
move_pool = self.pool.get('stock.move')
629
proc_pool = self.pool.get('procurement.order')
630
pts_pool = self.pool.get('delivery.time')
631
drl_pool = self.pool.get('delivery.route.line')
634
pts = pts_pool.browse(cr, uid, [pts_id])[0]
635
#self.write(cr, uid, ids, {'dts_id':pts and pts.dts_id and pts.dts_id.id or False})
636
res['dts_id'] = pts and pts.dts_id and pts.dts_id.id or False
638
move_ids = move_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('picking_id', 'in', ids)])
640
vals = {'pts_id':pts_id}
642
vals.update({'date_expected':pts.dts_id.start_date})
643
move_pool.write(cr, uid, move_ids, vals)
644
proc_ids = proc_pool.search(cr, uid, [('state', 'not in', ['cancel', 'done']), ('move_id', 'in', move_ids)])
646
proc_pool.write(cr, uid, proc_ids, {'pts_id':pts_id})
648
# Actually DONE in fields.function
649
# route_lines = drl_pool.search(cr, uid, [('state', 'in', ['draft']), ('picking_id', 'in', ids)])
650
# if route_lines and 'dts_id' in res:
651
# drl_pool.write(cr, uid, route_lines, {'dts_id': res['dts_id']})
652
return {'value': res}
655
def create(self, cr, uid, data, context=None):
659
if not data.get('pts_id', False) and data.get('origin', False):
660
so_obj = self.pool.get('sale.order')
661
so_ids = so_obj.search(cr, uid, [('name', '=', data.get('origin'))]) or []
662
for so in so_obj.browse(cr, uid, so_ids):
663
data.update({'pts_id':so.pts_id and so.pts_id.id or False, 'dts_id':so.pts_id and so.pts_id.dts_id and so.pts_id.dts_id.id or False})
665
purchase_id = data.get('purchase_id', False)
666
return_type = data.get('return', 'none')
668
po = self.pool.get('purchase.order').browse(cr, uid, purchase_id)
669
if not po.is_collected:
672
sp = super(stock_picking_in, self).create(cr, uid, data, context=context)
673
if data.get('pts_id', False) and return_type not in ['customer', 'supplier'] and not purchase_id:
674
self.pool.get('delivery.route.line').create(cr, uid, {'picking_id':sp, })
680
class stock_tracking(osv.osv):
681
_inherit = "stock.tracking"
684
'picking_id': fields.many2one('stock.picking', 'Picking Related', change_default=True),
685
'ul_id': fields.many2one('product.ul', 'Picking Box', change_default=True),
690
class mrp_production(osv.osv):
691
_inherit = 'mrp.production'
694
'pts_id': fields.many2one('delivery.time', 'Preparation Time', select=True, domain=[('type', '=', 'pts')]),
697
def _make_production_internal_shipment_line(self, cr, uid, production_line, shipment_id, parent_move_id, destination_location_id=False, context=None):
698
stock_move = self.pool.get('stock.move')
699
production = production_line.production_id
700
date_planned = production.date_planned
701
# Internal shipment is created for Stockable and Consumer Products
702
if production_line.product_id.type not in ('product', 'consu'):
704
source_location_id = production.location_src_id.id
705
if not destination_location_id:
706
destination_location_id = source_location_id
707
return stock_move.create(cr, uid, {
708
'name': production.name,
709
'picking_id': shipment_id,
710
'product_id': production_line.product_id.id,
711
'product_qty': production_line.product_qty,
712
'product_uom': production_line.product_uom.id,
713
'product_uos_qty': production_line.product_uos and production_line.product_uos_qty or False,
714
'product_uos': production_line.product_uos and production_line.product_uos.id or False,
715
'date': date_planned,
716
'move_dest_id': parent_move_id,
717
'location_id': source_location_id,
718
'location_dest_id': destination_location_id,
720
'company_id': production.company_id.id,
721
'pts_id': production.pts_id and production.pts_id.id or False,
724
def _make_production_internal_shipment(self, cr, uid, production, context=None):
725
ir_sequence = self.pool.get('ir.sequence')
726
stock_picking = self.pool.get('stock.picking')
728
pick_type = 'internal'
731
# Take routing address as a Shipment Address.
732
# If usage of routing location is a internal, make outgoing shipment otherwise internal shipment
733
if production.bom_id.routing_id and production.bom_id.routing_id.location_id:
734
routing_loc = production.bom_id.routing_id.location_id
735
if routing_loc.usage != 'internal':
737
partner_id = routing_loc.partner_id and routing_loc.partner_id.id or False
739
# Take next Sequence number of shipment base on type
740
# SHOULD USE ir_sequence.next_by_code() or ir_sequence.next_by_id()
741
pick_name = ir_sequence.get(cr, uid, 'stock.picking.' + pick_type)
743
picking_id = stock_picking.create(cr, uid, {
745
'origin': (production.origin or '').split(':')[0] + ':' + production.name,
749
'partner_id': partner_id,
750
'auto_picking': self._get_auto_picking(cr, uid, production),
751
'company_id': production.company_id.id,
752
'pts_id': production.pts_id and production.pts_id.id or False,
753
'dts_id': production.pts_id and production.pts_id.dts_id and production.pts_id.dts_id.id or False,
755
production.write({'picking_id': picking_id}, context=context)
758
def _make_production_produce_line(self, cr, uid, production, context=None):
759
stock_move = self.pool.get('stock.move')
760
source_location_id = production.product_id.property_stock_production.id
761
destination_location_id = production.location_dest_id.id
763
'name': production.name,
764
'date': production.date_planned,
765
'product_id': production.product_id.id,
766
'product_qty': production.product_qty,
767
'product_uom': production.product_uom.id,
768
'product_uos_qty': production.product_uos and production.product_uos_qty or False,
769
'product_uos': production.product_uos and production.product_uos.id or False,
770
'location_id': source_location_id,
771
'location_dest_id': destination_location_id,
772
'move_dest_id': production.move_prod_id.id,
774
'company_id': production.company_id.id,
775
'pts_id': production.pts_id and production.pts_id.id or False,
777
move_id = stock_move.create(cr, uid, data, context=context)
778
production.write({'move_created_ids': [(6, 0, [move_id])]}, context=context)
781
def _make_production_consume_line(self, cr, uid, production_line, parent_move_id, source_location_id=False, context=None):
782
stock_move = self.pool.get('stock.move')
783
production = production_line.production_id
784
# Internal shipment is created for Stockable and Consumer Products
785
if production_line.product_id.type not in ('product', 'consu'):
787
destination_location_id = production.product_id.property_stock_production.id
788
if not source_location_id:
789
source_location_id = production.location_src_id.id
790
move_id = stock_move.create(cr, uid, {
791
'name': production.name,
792
'date': production.date_planned,
793
'product_id': production_line.product_id.id,
794
'product_qty': production_line.product_qty,
795
'product_uom': production_line.product_uom.id,
796
'product_uos_qty': production_line.product_uos and production_line.product_uos_qty or False,
797
'product_uos': production_line.product_uos and production_line.product_uos.id or False,
798
'location_id': source_location_id,
799
'location_dest_id': destination_location_id,
800
'move_dest_id': parent_move_id,
802
'company_id': production.company_id.id,
803
'pts_id': production.pts_id and production.pts_id.id or False,
805
production.write({'move_lines': [(4, move_id)]}, context=context)
811
class procurement_order(osv.osv):
812
_inherit = 'procurement.order'
815
'pts_id': fields.many2one('delivery.time', 'Preparation Time', select=True, domain=[('type', '=', 'pts')]),
816
'message': fields.char(_('Latest error'), size=2048, help="Exception occurred while computing procurement orders."),
819
def make_mo(self, cr, uid, ids, context=None):
820
""" Make Manufacturing(production) order from procurement
821
@return: New created Production Orders procurement wise
824
company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
825
production_obj = self.pool.get('mrp.production')
826
move_obj = self.pool.get('stock.move')
827
wf_service = netsvc.LocalService("workflow")
828
procurement_obj = self.pool.get('procurement.order')
829
for procurement in procurement_obj.browse(cr, uid, ids, context=context):
830
res_id = procurement.move_id.id
831
newdate = datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.product_id.produce_delay or 0.0)
832
newdate = newdate - relativedelta(days=company.manufacturing_lead)
833
produce_id = production_obj.create(cr, uid, {
834
'origin': procurement.origin,
835
'product_id': procurement.product_id.id,
836
'product_qty': procurement.product_qty,
837
'product_uom': procurement.product_uom.id,
838
'product_uos_qty': procurement.product_uos and procurement.product_uos_qty or False,
839
'product_uos': procurement.product_uos and procurement.product_uos.id or False,
840
'location_src_id': procurement.location_id.id,
841
'location_dest_id': procurement.location_id.id,
842
'bom_id': procurement.bom_id and procurement.bom_id.id or False,
843
'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
844
'move_prod_id': res_id,
845
'company_id': procurement.company_id.id,
846
'pts_id': procurement.pts_id and procurement.pts_id.id or context and context.get('force_pts_id', False) or False,
849
res[procurement.id] = produce_id
850
self.write(cr, uid, [procurement.id], {'state': 'running', 'production_id': produce_id})
851
bom_result = production_obj.action_compute(cr, uid,
852
[produce_id], properties=[x.id for x in procurement.property_ids])
853
wf_service.trg_validate(uid, 'mrp.production', produce_id, 'button_confirm', cr)
855
move_obj.write(cr, uid, [res_id], {'location_id': procurement.location_id.id})
856
self.production_order_create_note(cr, uid, ids, context=context)
862
class delivery_time(osv.osv):
863
_inherit = 'delivery.time'
865
def search(self, cr, uid, args, offset=0, limit=None, order='name', context=None, count=False):
866
# now = datetime.now()
867
# args.append(('name','>=',datetime.strftime(now,'%y%m%d')))
868
return super(delivery_time, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)
873
class delivery_return_type(osv.osv):
874
_name = 'delivery.return.type'
877
'name': fields.char('Name', size=64, required=True, select=True),
878
'sequence': fields.integer('Sequence'),
881
delivery_return_type()
884
class delivery_return_reason(osv.osv):
885
_name = 'delivery.return.reason'
888
'type': fields.many2one('delivery.return.type', 'Type', required=True),
889
'reason': fields.char('Name', size=1024, required=False),
890
'route_line_id': fields.many2one('delivery.route.line', 'Delivery Route Line'),
892
delivery_return_reason()
895
class delivery_route(osv.osv):
896
_inherit = 'delivery.route'
898
def _auto_init(self, cr, context=None):
899
super(delivery_route, self)._auto_init(cr, context=context)
900
cr.execute("SELECT table_name FROM information_schema.tables WHERE table_name = 'delivery_scheduler_running'")
901
if not cr.fetchone():
902
cr.execute('CREATE TABLE delivery_scheduler_running (running boolean)')
904
cr.execute('INSERT INTO delivery_scheduler_running (running) VALUES (FALSE)')
906
def set_confirm_cs(self, cr, uid, ids, context=None):
907
self.write(cr, uid, ids, {'confirm_cs': True}, context=context)
913
class delivery_route_line(osv.osv):
914
_inherit = 'delivery.route.line'
916
def search(self, cr, uid, args, offset=0, limit=None, order='dts_name', context=None, count=False):
917
context = context or {}
918
new_order = context.get('sorting', order)
919
return super(delivery_route_line, self).search(cr, uid, args, offset=offset, limit=limit, order=new_order, context=context, count=count)
921
def set_not_vip(self, cr, uid, ids, context=None):
922
return self.write(cr, uid, ids, {'vip':False})
924
def set_vip(self, cr, uid, ids, context=None):
925
return self.write(cr, uid, ids, {'vip':True})
927
def write(self, cr, uid, ids, vals, context=None):
928
if type(ids) != type([]):
930
context = context or {}
931
if ('route_id' in vals or 'color' in vals or 'sequence' in vals) and not 'force_update' in context:
932
for line in self.browse(cr, uid, ids):
933
if line.state == 'draft':
934
current_dts = context.get('force_dts_id_kanban', False) or False
936
# vals.update({'dts_id':current_dts})
937
if 'route_id' in vals and vals['route_id']:
938
route_state = self.pool.get('delivery.route').read(cr, uid, [vals['route_id']], ['state', 'name'])
939
if route_state[0]['state'] != 'draft':
940
print('The Route %s is confirmed, you can not add lines to it.' % (route_state[0]['name']))
941
raise osv.except_osv(_('Error'), _('The Route %s is confirmed, you can not add lines to it.' % (route_state[0]['name'])))
943
elif 'update_color' in context and context['update_color'] == 1:
944
current_color = str(line.color)
945
cr.execute("SELECT color FROM (select count(*) as cpt, color as color from delivery_route_line WHERE route_id=" + str(vals['route_id']) + " AND color != " + current_color + " AND color IS NOT null AND color > 0 GROUP BY color) t ORDER BY cpt DESC")
946
color = cr.fetchone()
947
if color and color[0]:
948
vals.update({'color':color[0]})
951
cr.execute("SELECT DISTINCT color FROM delivery_route_line WHERE (dts_id=" + str(current_dts) + " OR id = " + str(line.id) + ") AND color IS NOT null AND color > 0")
952
colors = map(lambda x: x[0], cr.fetchall())
955
for idx in range(1, 22):
956
if idx not in colors and not color and idx != current_color:
959
vals.update({'color':color})
961
print('No more Route available for the DTS %s.' % (line.dts_id.name))
962
raise osv.except_osv(_('Error'), _('No more Route available for the DTS %s.' % (line.dts_id.name)))
964
elif 'check4color' in context and context['check4color'] and 'color' in vals:
965
cr.execute("SELECT DISTINCT route_id FROM delivery_route_line WHERE dts_id=" + str(line.dts_id.id) + " AND color = " + str(vals['color']) + " AND color > 0 AND state not in ('draft','cancel')")
966
route_line_ids = map(lambda x: x[0], cr.fetchall())
968
print('The Route Line %s (origin: %s) can not be put in a confirmed Route (%s).' % (line.picking_id.name, line.picking_id.origin, route_line_ids))
969
raise osv.except_osv(_('Error'), _('The Route Line %s (origin: %s) can not be put in a confirmed Route (%s).' % (line.picking_id.name, line.picking_id.origin, route_line_ids)))
971
print('The Route Line %s (origin: %s) is confirmed. You can not change it.' % (line.picking_id.name, line.picking_id.origin))
972
raise osv.except_osv(_('Error'), _('The Route Line %s (origin: %s) is confirmed. You can not change it.' % (line.picking_id.name, line.picking_id.origin)))
973
return super(delivery_route_line, self).write(cr, uid, ids, vals, context=context)
976
def set_van(self, cr, uid, ids, van=0, context=None):
977
self.write(cr, uid, ids, {'color': van}, context=context)
979
def set_van_0(self, cr, uid, ids, context=None):
980
return self.set_van(cr, uid, ids, 0, context)
981
def set_van_1(self, cr, uid, ids, context=None):
982
return self.set_van(cr, uid, ids, 1, context)
983
def set_van_2(self, cr, uid, ids, context=None):
984
return self.set_van(cr, uid, ids, 2, context)
985
def set_van_3(self, cr, uid, ids, context=None):
986
return self.set_van(cr, uid, ids, 3, context)
987
def set_van_4(self, cr, uid, ids, context=None):
988
return self.set_van(cr, uid, ids, 4, context)
989
def set_van_5(self, cr, uid, ids, context=None):
990
return self.set_van(cr, uid, ids, 5, context)
991
def set_van_6(self, cr, uid, ids, context=None):
992
return self.set_van(cr, uid, ids, 6, context)
993
def set_van_7(self, cr, uid, ids, context=None):
994
return self.set_van(cr, uid, ids, 7, context)
995
def set_van_8(self, cr, uid, ids, context=None):
996
return self.set_van(cr, uid, ids, 8, context)
997
def set_van_9(self, cr, uid, ids, context=None):
998
return self.set_van(cr, uid, ids, 9, context)
1001
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
1002
context = context or {}
1003
if 'view_name' in context and view_type == 'kanban':
1004
view_ids = self.pool.get('ir.ui.view').search(cr, uid, [('model', '=', 'delivery.route.line'), ('name', '=', context['view_name'])], context=context)
1006
view_id = view_ids[0]
1007
del context['view_name']
1008
return super(delivery_route_line, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
1011
def _get_neighborhood(self, cr, uid, ids, fields, args, context=None):
1013
for route in self.browse(cr, uid, ids):
1014
# res[route.id] = route.picking_id and route.picking_id.sale_id and route.picking_id.sale_id.deliver_zone or route.picking_id and route.picking_id.partner_id and route.picking_id.partner_id.vm_district or False
1015
res[route.id] = route.picking_id and route.picking_id.partner_id and route.picking_id.partner_id.deliver_zone or False
1018
def _get_dts_id(self, cr, uid, ids, fields, args, context=None):
1019
context = context or {}
1021
for route in self.browse(cr, uid, ids):
1022
if route.state in ['draft'] and context.get('set_dts', True):
1023
res[route.id] = route.picking_id and route.picking_id.pts_id and route.picking_id.pts_id.dts_id and route.picking_id.pts_id.dts_id.id or False
1025
res[route.id] = route.dts_id and route.dts_id.id or False
1028
def _get_dts_name(self, cr, uid, ids, fields, args, context=None):
1029
context = context or {}
1031
for route in self.browse(cr, uid, ids):
1032
if route.state in ['draft'] and context.get('set_dts', True):
1033
res[route.id] = route.picking_id and route.picking_id.pts_id and route.picking_id.pts_id.dts_id and route.picking_id.pts_id.dts_id.name or 'n/a'
1035
res[route.id] = route.dts_name or 'n/a'
1038
def _get_special_time(self, cr, uid, ids, fields, args, context=None):
1039
tz = pytz.timezone('Asia/Shanghai')
1041
for route in self.browse(cr, uid, ids):
1044
route_dts_id = route.dts_id and route.dts_id.id
1045
so_dts_id = route.picking_id.sale_id.dts_id and route.picking_id.sale_id.dts_id.id
1047
if so_dts_id and route_dts_id != so_dts_id:
1048
customer_date = route.picking_id.sale_id.dts_id.name
1050
elif route.picking_id.sale_id:
1051
date_start = route.picking_id.sale_id.start_date or False
1052
date_end = route.picking_id.sale_id.end_date or False
1055
date_start = datetime.strptime(date_start, '%Y-%m-%d %H:%M:%S')
1056
date_start = pytz.utc.localize(date_start).astimezone(tz)
1058
customer_date = datetime.strftime(date_start, '%H:%M')
1059
#LY if customer_date is 00:00, no special time.
1060
if customer_date != '00:00':
1062
date_end = datetime.strptime(date_end, '%Y-%m-%d %H:%M:%S')
1063
date_end = pytz.utc.localize(date_end).astimezone(tz)
1064
customer_date += ' - '
1065
customer_date += datetime.strftime(date_end, '%H:%M')
1066
res['customer_date'] = customer_date or ' '
1067
result[route.id] = res
1070
def _get_street(self, cr, uid, ids, fields, args, context=None):
1072
for route in self.browse(cr, uid, ids):
1073
res[route.id] = route.picking_id and route.picking_id.partner_id and route.picking_id.partner_id.street or ' n/a'
1076
def _route_to_update_after_picking_change(self, cr, uid, ids, fields=None, arg=None, context=None):
1077
if type(ids) != type([]):
1079
return self.pool.get('delivery.route.line').search(cr, uid, [('picking_id', 'in', ids)]) or []
1081
def _route_to_update_after_dts_change(self, cr, uid, ids, fields=None, arg=None, context=None):
1082
if type(ids) != type([]):
1084
picking_ids = self.pool.get('stock.picking').search(cr, uid, [('dts_id', 'in', ids)]) or []
1085
return self.pool.get('delivery.route.line')._route_to_update_after_picking_change(cr, uid, picking_ids, None, None, context=context)
1087
def _route_to_update_after_so_change(self, cr, uid, ids, fields=None, arg=None, context=None):
1088
if type(ids) != type([]):
1090
return self.pool.get('delivery.route.line').search(cr, uid, [('sale_order_id', 'in', ids)]) or []
1092
def _route_to_update_after_po_change(self, cr, uid, ids, fields=None, arg=None, context=None):
1093
if type(ids) != type([]):
1095
return self.pool.get('delivery.route.line').search(cr, uid, [('purchase_id', 'in', ids)]) or []
1097
def _route_to_update_after_partner_change(self, cr, uid, ids, fields=None, arg=None, context=None):
1098
if type(ids) != type([]):
1100
picking_ids = self.pool.get('stock.picking').search(cr, uid, [('partner_id', 'in', ids)]) or []
1101
return self.pool.get('delivery.route.line')._route_to_update_after_picking_change(cr, uid, picking_ids, None, None, context=context)
1104
'delivery.route.line': (lambda self, cr, uid, ids, context: ids, ['picking_id'], 10),
1105
'stock.picking': (_route_to_update_after_picking_change, ['pts_id'], 10),
1108
'delivery.route.line': (lambda self, cr, uid, ids, context: ids, ['picking_id'], 10),
1109
'stock.picking': (_route_to_update_after_picking_change, ['pts_id'], 10),
1110
'delivery.time': (_route_to_update_after_dts_change, ['name'], 10),
1112
_store_special_time = {
1113
'delivery.route.line': (lambda self, cr, uid, ids, context: ids, ['picking_id'], 12),
1114
'stock.picking': (_route_to_update_after_picking_change, ['sale_id','dts_id'], 12),
1115
'sale.order': (_route_to_update_after_so_change, ['dts_id'], 12),
1117
_store_neighborhood = {
1118
'delivery.route.line': (lambda self, cr, uid, ids, context: ids, ['picking_id'], 10),
1119
'stock.picking': (_route_to_update_after_picking_change, ['partner_id'], 10),
1120
'res.partner': (_route_to_update_after_partner_change, ['vm_district'], 10),
1124
'delivery.route.line': (lambda self, cr, uid, ids, context: ids, ['picking_id', 'adjustment'], 10),
1125
'stock.picking': (_route_to_update_after_picking_change, ['sale_id', 'purchase_id', 'origin'], 10),
1126
'purchase.order': (_route_to_update_after_po_change, ['amount_total'], 10),
1130
'delivery.route.line': (lambda self,cr,uid,ids,context: ids,['picking_id'],10),
1131
'stock.picking': (_route_to_update_after_picking_change, ['partner_id'], 10),
1134
def _get_amount(self, cr, uid, ids, fields, args, context=None):
1136
for route in self.browse(cr, uid, ids):
1138
res['amount_total'] = 0.0
1139
res['amount_unpaid'] = 0.0
1140
res['to_be_received'] = 0.0
1142
if route.picking_id and route.picking_id.sale_id:
1143
res['amount_total'] = route.picking_id.sale_id.amount_total
1144
res['amount_unpaid'] = res['amount_total']
1145
res['to_be_received'] = res['amount_unpaid'] + route.adjustment
1146
elif route.picking_id and route.picking_id.purchase_id:
1147
res['amount_total'] = route.picking_id.purchase_id.amount_total
1148
res['amount_unpaid'] = 0.0
1149
res['to_be_received'] = res['amount_unpaid'] + route.adjustment
1150
result[route.id] = res
1154
'dts_id': fields.function(_get_dts_id, type='many2one', obj='delivery.time', store=_store_dts, string='Delivery Time', _classic_read=True),
1155
'dts_name': fields.function(_get_dts_name, type='char', size=124, store=_store_dts_name, string='Delivery Time'),
1156
'return_reasons': fields.one2many('delivery.return.reason', 'route_line_id', 'Return Reasons', readonly=False),
1157
'delivered_cpt': fields.related('picking_id', 'delivered_cpt', type='integer', string='Delivered x times', readonly=True),
1158
'customer_date': fields.function(_get_special_time, type='char', size=64, store=_store_special_time, multi="special_time", string=_('Customer Delivery Time')),
1159
'neighborhood': fields.function(_get_neighborhood, type='char', size=255, store=_store_neighborhood, string=_('Neighborhood')),
1160
'street': fields.function(_get_street, type='char', size=128, store=_store_street, string='Street'),
1161
'vip': fields.boolean('is VIP ?'),
1162
'amount_total': fields.function(_get_amount, type='float', multi="amount", store=_store_amount, string='Total'),
1163
'amount_unpaid': fields.function(_get_amount, type='float', multi="amount", store=_store_amount, string='Unpaid'),
1164
'adjustment': fields.float('Adjustment'),
1165
'cs_remark': fields.text('CS Remark'),
1166
'to_be_received': fields.function(_get_amount, type='float', multi="amount", store=_store_amount, string='To be Received'),
1167
'amount_received': fields.float('Received'),
1168
'account_checked': fields.boolean('Checked'),
1169
'account_remark': fields.text('Remark Accounting'),
1171
delivery_route_line()
1174
class res_users(osv.osv):
1175
_inherit = 'res.users'
1178
'dts_id': fields.many2one('delivery.time', 'Last Used Delivery Time'),
1182
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: