Add some missing config files
[odoo/odoo.git] / addons / auction / auction.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 # Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
5 #                   Fabien Pinckaers <fp@tiny.Be>
6 #
7 # WARNING: This program as such is intended to be used by professional
8 # programmers who take the whole responsability of assessing all potential
9 # consequences resulting from its eventual inadequacies and bugs
10 # End users who are looking for a ready-to-use solution with commercial
11 # garantees and support are strongly adviced to contract a Free Software
12 # Service Company
13 #
14 # This program is Free Software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; either version 2
17 # of the License, or (at your option) any later version.
18 #
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27 #
28 ##############################################################################
29
30 import time
31 import netsvc
32 from osv import fields, osv, orm
33 import ir
34 from mx import DateTime
35
36 #----------------------------------------------------------
37 # Auction Artists
38 #----------------------------------------------------------
39 class auction_artists(osv.osv):
40     _name = "auction.artists"
41     _columns = {
42         'name': fields.char('Artist/Author Name', size=64, required=True),
43         'pseudo': fields.char('Pseudo', size=64),
44         'birth_death_dates':fields.char('Birth / Death dates',size=64),
45         'biography': fields.text('Biography'),
46     }
47 auction_artists()
48
49 #----------------------------------------------------------
50 # Auction Dates
51 #----------------------------------------------------------
52 class auction_dates(osv.osv):
53     _name = "auction.dates"
54
55     def _adjudication_get(self, cr, uid, ids, prop, unknow_none,unknow_dict):
56         tmp={}
57         for id in ids:
58             tmp[id]=0.0
59             cr.execute("select sum(obj_price) from auction_lots where auction_id=%d", (id,))
60             sum = cr.fetchone()
61             if sum:
62                 tmp[id]=sum[0]
63         return tmp
64
65     def name_get(self, cr, uid, ids, context={}):
66         if not len(ids):
67             return []
68         reads = self.read(cr, uid, ids, ['name', 'auction1'], context)
69         name = [(r['id'],'['+r['auction1']+'] '+ r['name']) for r in reads]
70         return name
71
72     _columns = {
73         'name': fields.char('Auction date', size=64, required=True),
74         'expo1': fields.date('First Exposition Day', required=True),
75         'expo2': fields.date('Last Exposition Day', required=True),
76         'auction1': fields.date('First Auction Day', required=True),
77         'auction2': fields.date('Last Auction Day', required=True),
78         'journal_id': fields.many2one('account.journal', 'Buyer Journal', required=True),
79         'journal_seller_id': fields.many2one('account.journal', 'Seller Journal', required=True),
80         'buyer_costs': fields.many2many('account.tax', 'auction_buyer_taxes_rel', 'auction_id', 'tax_id', 'Buyer Costs'),
81         'seller_costs': fields.many2many('account.tax', 'auction_seller_taxes_rel', 'auction_id', 'tax_id', 'Seller Costs'),
82         'acc_income': fields.many2one('account.account', 'Income Account', required=True),
83         'acc_expense': fields.many2one('account.account', 'Expense Account', required=True),
84         'adj_total': fields.function(_adjudication_get, method=True, string='Total Adjudication',store=True),
85         'state': fields.selection((('draft','Draft'),('close','Closed')),'Status',select=1, readonly=True),
86         'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True),
87
88     }
89     _defaults = {
90         'state': lambda *a: 'draft',
91     }
92     _order = "auction1 desc"
93
94     def close(self, cr, uid, ids, *args):
95         print "GGGGGGGGGGGGGGGggg"
96         """
97         Close an auction date.
98
99         Create invoices for all buyers and sellers.
100         STATE ='close'
101
102         RETURN: True
103         """
104         # objects vendus mais non factures
105         cr.execute('select count(*) as c from auction_lots where auction_id in ('+','.join(map(str,ids))+') and state=%s and obj_price>0', ('draft',))
106         nbr = cr.fetchone()[0]
107         ach_uids = {}
108         cr.execute('select id from auction_lots where auction_id in ('+','.join(map(str,ids))+') and state=%s and obj_price>0', ('draft',))
109         r=self.pool.get('auction.lots').lots_invoice(cr, uid, [x[0] for x in cr.fetchall()],{},None)
110         print "RRRRRRRRRRRRRRRRrrrr",r
111         cr.execute('select id from auction_lots where auction_id in ('+','.join(map(str,ids))+') and obj_price>0')
112         ids2 = [x[0] for x in cr.fetchall()]
113     #   for auction in auction_ids:
114         c=self.pool.get('auction.lots').seller_trans_create(cr, uid, ids2,{})
115         self.write(cr, uid, ids, {'state':'closed'}) #close the auction
116         print "jjjjjjjjjjjjjjjj"
117         return True
118 auction_dates()
119
120
121 #----------------------------------------------------------
122 # Deposits
123 #----------------------------------------------------------
124 def _inv_uniq(cr, ids):
125     cr.execute('select name from auction_deposit where id in ('+','.join(map(lambda x: str(x), ids))+')')
126     for datas in cr.fetchall():
127         cr.execute('select count(*) from auction_deposit where name=%s', (datas[0],))
128         if cr.fetchone()[0]>1:
129             return False
130     return True
131
132 class auction_deposit(osv.osv):
133     _name = "auction.deposit"
134     _description="Deposit Border"
135     _order = "id desc"
136     _columns = {
137         'transfer' : fields.boolean('Transfer'),
138         'name': fields.char('Depositer Inventory', size=64, required=True),
139         'partner_id': fields.many2one('res.partner', 'Seller', required=True, change_default=True),
140         'date_dep': fields.date('Deposit date', required=True),
141         'method': fields.selection((('keep','Keep until sold'),('decease','Decrease limit of 10%'),('contact','Contact the Seller')), 'Withdrawned method', required=True),
142         'tax_id': fields.many2one('account.tax', 'Expenses'),
143         'create_uid': fields.many2one('res.users', 'Created by', readonly=True),
144         'info': fields.char('Description', size=64),
145         'lot_id': fields.one2many('auction.lots', 'bord_vnd_id', 'Objects'),
146         'specific_cost_ids': fields.one2many('auction.deposit.cost', 'deposit_id', 'Specific Costs'),
147         'total_neg': fields.boolean('Allow Negative Amount'),
148     }
149     _defaults = {
150 #       'date_dep': lambda *a: time.strftime('%Y-%m-%d'),
151         'method': lambda *a: 'keep',
152         'total_neg': lambda *a: False,
153         'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'auction.deposit'),
154     }
155     _constraints = [
156     ]
157     def partner_id_change(self, cr, uid, ids, part):
158         return {}
159 auction_deposit()
160
161 #----------------------------------------------------------
162 # (Specific) Deposit Costs
163 #----------------------------------------------------------
164 class auction_deposit_cost(osv.osv):
165     _name = 'auction.deposit.cost'
166     _columns = {
167         'name': fields.char('Cost Name', required=True, size=64),
168         'amount': fields.float('Amount'),
169         'account': fields.many2one('account.account', 'Destination Account', required=True),
170         'deposit_id': fields.many2one('auction.deposit', 'Deposit'),
171     }
172 auction_deposit_cost()
173
174 #----------------------------------------------------------
175 # Lots Categories
176 #----------------------------------------------------------
177 class auction_lot_category(osv.osv):
178     _name = 'auction.lot.category'
179     _columns = {
180         'name': fields.char('Category Name', required=True, size=64),
181         'priority': fields.float('Priority'),
182         'active' : fields.boolean('Active'),
183         'aie_categ' : fields.selection([('41',"Unclassifieds"),
184             ('2',"Antiques"),
185             ('42',"Antique/African Arts"),
186             ('59',"Antique/Argenterie"),
187             ('45',"Antique/Art from the Ivory Coast"),
188             ('46',"Antique/Art from the Ivory Coast/African Arts"),
189             ('12',"Antique/Books, manuscripts, eso."),
190             ('11',"Antique/Carpet and textilles"),
191             ('14',"Antique/Cartoons"),
192             ('26',"Antique/Clocks and watches"),
193             ('31',"Antique/Collectible & art objects"),
194             ('33',"Antique/Engravings"),
195             ('10',"Antique/Furnitures"),
196             ('50',"Antique/Graphic Arts"),
197             ('37',"Antique/Jewelry"),
198             ('9',"Antique/Lightings"),
199             ('52',"Antique/Metal Ware"),
200             ('51',"Antique/Miniatures / Collections"),
201             ('53',"Antique/Musical Instruments"),
202             ('19',"Antique/Old weapons and militaria"),
203             ('43',"Antique/Oriental Arts"),
204             ('47',"Antique/Oriental Arts/Chineese furnitures"),
205             ('24',"Antique/Others"),
206             ('8',"Antique/Painting"),
207             ('25',"Antique/Porcelain, Ceramics, Glassmaking, ..."),
208             ('13',"Antique/Posters"),
209             ('56',"Antique/Religiosa"),
210             ('54',"Antique/Scientific Instruments"),
211             ('18',"Antique/Sculpture, bronze, eso."),
212             ('55',"Antique/Tin / Copper wares"),
213             ('16',"Antique/Toys"),
214             ('57',"Antique/Verreries"),
215             ('17',"Antique/Wine"),
216             ('1',"Contemporary Art"),
217             ('58',"Cont. Art/Arts"),
218             ('27',"Cont. Art/Curiosa"),
219             ('15',"Cont. Art/Jewelry"),
220             ('30',"Cont. Art/Other Media"),
221             ('3',"Cont. Art/Photo"),
222             ('4',"Cont. Art/Painting"),
223             ('5',"Cont. Art/Sculpture"),
224             ('48',"Cont. Art/Shows")],
225             'Aie Category'),
226     }
227     _defaults = {
228         'active' : lambda *a: 1,
229         'aie_categ' : lambda *a:1,
230     }
231 auction_lot_category()
232
233 def _type_get(self, cr, uid,ids):
234     cr.execute('select name, name from auction_lot_category order by name')
235     return cr.fetchall()
236
237 #----------------------------------------------------------
238 # Lots
239 #----------------------------------------------------------
240 def _inv_constraint(cr, ids):
241     cr.execute('select id, bord_vnd_id, lot_num from auction_lots where id in ('+','.join(map(lambda x: str(x), ids))+')')
242     for datas in cr.fetchall():
243         cr.execute('select count(*) from auction_lots where bord_vnd_id=%s and lot_num=%s', (datas[1],datas[2]))
244         if cr.fetchone()[0]>1:
245             return False
246     return True
247
248 class auction_lots(osv.osv):
249     _name = "auction.lots"
250     _order = "obj_num,lot_num,id"
251     _description="Object"
252
253     def button_not_bought(self,cr,uid,ids,*a):
254         return self.write(cr,uid,ids, {'state':'unsold'})
255     def button_taken_away(self,cr,uid,ids,*a):
256         return self.write(cr,uid,ids, {'state':'taken_away'})
257
258     def button_unpaid(self,cr,uid,ids,*a):
259         return self.write(cr,uid,ids, {'state':'draft'})
260
261     def button_draft(self,cr,uid,ids,*a):
262         return self.write(cr,uid,ids, {'state':'draft'})
263
264     def button_bought(self,cr,uid,ids,*a):
265         return self.write(cr,uid,ids, {'state':'sold'})
266
267     def _buyerprice(self, cr, uid, ids, name, args, context):
268         res={}
269         lots=self.pool.get('auction.lots').browse(cr,uid,ids)
270         pt_tax=self.pool.get('account.tax')
271         for lot in lots:
272             amount_total=0.0
273     #       if ((lot.obj_price==0) and (lot.state=='draft')):
274     #           montant=lot.lot_est1
275     #       else:
276             montant=lot.obj_price or 0.0
277             taxes = []
278             if lot.author_right:
279                 taxes.append(lot.author_right)
280             if lot.auction_id:
281                 taxes += lot.auction_id.buyer_costs
282             tax=pt_tax.compute(cr,uid,taxes,montant,1)
283             for t in tax:
284                 amount_total+=t['amount']
285             amount_total += montant
286             res[lot.id] = amount_total
287         return res
288
289
290     def _sellerprice(self, cr, uid, ids,*a):
291         res={}
292         lots=self.pool.get('auction.lots').browse(cr,uid,ids)
293         pt_tax=self.pool.get('account.tax')
294         for lot in lots:
295             amount_total=0.0
296         #   if ((lot.obj_price==0) and (lot.state=='draft')):
297         #       montant=lot.lot_est1
298         #   else:
299             montant=lot.obj_price
300             taxes = []
301             if lot.bord_vnd_id.tax_id:
302                 taxes.append(lot.bord_vnd_id.tax_id)
303             elif lot.auction_id and lot.auction_id.seller_costs:
304                 taxes += lot.auction_id.seller_costs
305             tax=pt_tax.compute(cr,uid,taxes,montant,1)
306             for t in tax:
307                 amount_total+=t['amount']
308             res[lot.id] =  montant+amount_total
309         return res
310
311     def _grossprice(self, cr, uid, ids, name, args, context):
312         """gross revenue"""
313         res={}
314         auction_lots_obj = self.read(cr,uid,ids,['seller_price','buyer_price','auction_id'])
315         for auction_data in auction_lots_obj:
316             total_tax = 0.0
317             if auction_data['auction_id']:
318                 total_tax += auction_data['buyer_price']-auction_data['seller_price']
319             res[auction_data['id']] = total_tax
320         return res
321
322
323     def _grossmargin(self, cr, uid, ids, name, args, context):
324         """
325         gross Margin : Gross revenue * 100 / Adjudication
326         (state==unsold or obj_ret_price>0): adj_price = 0 (=> gross margin = 0, net margin is negative)
327         """
328         res={}
329         for lot in self.browse(cr, uid, ids, context):
330             if ((lot.obj_price==0) and (lot.state=='draft')):
331                 montant=lot.lot_est1
332             else:
333                 montant=lot.obj_price
334             if lot.obj_price>0:
335                 total=(lot.gross_revenue*100.0) /lot.obj_price
336             else:
337                 total = 0.0
338             res[lot.id]=round(total,2)
339         return res
340
341     def onchange_obj_ret(self, cr, uid, ids, obj_ret, *args):
342         if obj_ret:
343             return {'value': {'obj_price': 0}}
344         return {}
345
346     def _costs(self,cr,uid,ids,context,*a):
347         """
348         costs: Total credit of analytic account
349         / # objects sold during this auction
350         (excluding analytic lines that are in the analytic journal of the auction date).
351         """
352         res={}
353         for lot in self.browse(cr,uid,ids):
354             som=0.0
355             if not lot.auction_id:
356                 res[lot.id] = 0.0
357                 continue
358             auct_id=lot.auction_id.id
359             cr.execute('select count(*) from auction_lots where auction_id=%d', (auct_id,))
360             nb = cr.fetchone()[0]
361             account_analytic_line_obj = self.pool.get('account.analytic.line')
362             line_ids = account_analytic_line_obj.search(cr, uid, [('account_id', '=', lot.auction_id.account_analytic_id.id),('journal_id', '<>', lot.auction_id.journal_id.id),('journal_id', '<>', lot.auction_id.journal_seller_id.id)])
363             #indir_cost=lot.bord_vnd_id.specific_cost_ids
364             #for r in lot.bord_vnd_id.specific_cost_ids:
365             #   som+=r.amount
366
367             for line in account_analytic_line_obj.browse(cr,uid,line_ids):
368                 if line.amount:
369                     som-=line.amount
370             res[lot.id]=som/nb
371         return res
372
373     def _netprice(self, cr, uid, ids, name, args, context):
374         """This is the net revenue"""
375         res={}
376         auction_lots_obj = self.read(cr,uid,ids,['seller_price','buyer_price','auction_id','costs'])
377         for auction_data in auction_lots_obj:
378             total_tax = 0.0
379             if auction_data['auction_id']:
380                 total_tax += auction_data['buyer_price']-auction_data['seller_price']-auction_data['costs']
381             res[auction_data['id']] = total_tax
382         return res
383
384     def _netmargin(self, cr, uid, ids, name, args, context):
385         res={}
386         total_tax = 0.0
387         total=0.0
388         montant=0.0
389         auction_lots_obj = self.read(cr,uid,ids,['net_revenue','auction_id','lot_est1','obj_price','state'])
390         for auction_data in auction_lots_obj:
391             if ((auction_data ['obj_price']==0) and (auction_data['state']=='draft')):
392                 montant=auction_data['lot_est1']
393             else: montant=auction_data ['obj_price']
394             if montant>0:
395                 total_tax += (auction_data['net_revenue']*100)/montant
396             else:
397                 total_tax=0
398             res[auction_data['id']] =  total_tax
399         return res
400
401     def _is_paid_vnd(self,cr,uid,ids,*a):
402         res = {}
403         lots=self.browse(cr,uid,ids)
404         for lot in lots:
405             res[lot.id] = False
406             if lot.sel_inv_id:
407                 if lot.sel_inv_id.state == 'paid':
408                     res[lot.id] = True
409         return res
410     def _is_paid_ach(self,cr,uid,ids,*a):
411         res = {}
412         lots=self.browse(cr,uid,ids)
413         for lot in lots:
414             res[lot.id] = False
415             if lot.ach_inv_id:
416                 if lot.ach_inv_id.state == 'paid':
417                     res[lot.id] = True
418         return res
419     _columns = {
420         'bid_lines':fields.one2many('auction.bid_line','lot_id', 'Bids'),
421         'auction_id': fields.many2one('auction.dates', 'Auction Date', select=1),
422         'bord_vnd_id': fields.many2one('auction.deposit', 'Depositer Inventory', required=True),
423         'name': fields.char('Short Description',size=64, required=True),
424         'name2': fields.char('Short Description (2)',size=64),
425         'lot_type': fields.selection(_type_get, 'Object category', size=64),
426         'author_right': fields.many2one('account.tax', 'Author rights'),
427         'lot_est1': fields.float('Minimum Estimation'),
428         'lot_est2': fields.float('Maximum Estimation'),
429         'lot_num': fields.integer('List Number', required=True, select=1 ),
430         'create_uid': fields.many2one('res.users', 'Created by', readonly=True),
431         'history_ids':fields.one2many('auction.lot.history', 'lot_id', 'Auction history'),
432         'lot_local':fields.char('Location',size=64),
433         'artist_id':fields.many2one('auction.artists', 'Artist/Author'),
434         'artist2_id':fields.many2one('auction.artists', 'Artist/Author 2'),
435         'important':fields.boolean('To be Emphatized'),
436         'product_id':fields.many2one('product.product', 'Product', required=True),
437         'obj_desc': fields.text('Object Description'),
438         'obj_num': fields.integer('Catalog Number'),
439         'obj_ret': fields.float('Price retired'),
440         'obj_comm': fields.boolean('Commission'),
441         'obj_price': fields.float('Adjudication price'),
442         'ach_avance': fields.float('Buyer Advance'),
443         'ach_login': fields.char('Buyer Username',size=64),
444         'ach_uid': fields.many2one('res.partner', 'Buyer'),
445         'ach_emp': fields.boolean('Taken Away'),
446         'is_ok': fields.boolean('Buyer s payment'),
447         'ach_inv_id': fields.many2one('account.invoice','Buyer Invoice', readonly=True, states={'draft':[('readonly',False)]}),
448         'sel_inv_id': fields.many2one('account.invoice','Seller Invoice', readonly=True, states={'draft':[('readonly',False)]}),
449         'vnd_lim': fields.float('Seller limit'),
450         'vnd_lim_net': fields.boolean('Net limit ?',readonly=True),
451         'image': fields.binary('Image'),
452 #       'paid_vnd':fields.function(_is_paid_vnd,string='Seller Paid',method=True,type='boolean',store=True),
453         'paid_vnd':fields.boolean('Seller Paid'),
454         'paid_ach':fields.function(_is_paid_ach,string='Buyer invoice reconciled',method=True, type='boolean',store=True),
455         'state': fields.selection((('draft','Draft'),('unsold','Unsold'),('paid','Paid'),('sold','Sold'),('taken_away','Taken away')),'Status', required=True, readonly=True),
456         'buyer_price': fields.function(_buyerprice, method=True, string='Buyer price',store=True),
457         'seller_price': fields.function(_sellerprice, method=True, string='Seller price',store=True),
458         'gross_revenue':fields.function(_grossprice, method=True, string='Gross revenue',store=True),
459         'gross_margin':fields.function(_grossmargin, method=True, string='Gross Margin (%)',store=True),
460         'costs':fields.function(_costs,method=True,string='Indirect costs',store=True),
461         'statement_id': fields.many2many('account.bank.statement.line', 'auction_statement_line_rel','auction_id', 'statement','Payment'),
462         'net_revenue':fields.function(_netprice, method=True, string='Net revenue',store=True),
463         'net_margin':fields.function(_netmargin, method=True, string='Net Margin (%)',store=True),
464     }
465     _defaults = {
466         'state':lambda *a: 'draft',
467         'lot_num':lambda *a:1,
468         'is_ok': lambda *a: False
469     }
470     _constraints = [
471 #       (_inv_constraint, 'Twice the same inventory number !', ['lot_num','bord_vnd_id'])
472     ]
473
474
475     def name_get(self, cr, user, ids, context={}):
476         if not len(ids):
477             return []
478         result = [ (r['id'], str(r['obj_num'])+' - '+r['name']) for r in self.read(cr, user, ids, ['name','obj_num'])]
479         return result
480
481     def name_search(self, cr, user, name, args=[], operator='ilike', context={}):
482         try:
483             ids = self.search(cr, user, [('obj_num','=',int(name))]+ args)
484         except:
485             ids = []
486         if not ids:
487             ids = self.search(cr, user, [('name',operator,name)]+ args)
488         return self.name_get(cr, user, ids)
489
490     def _sum_taxes_by_type_and_id(self, taxes):
491         """
492         PARAMS: taxes: a list of dictionaries of the form {'id':id, 'amount':amount, ...}
493         RETURNS : a list of dictionaries of the form {'id':id, 'amount':amount, ...}; one dictionary per unique id.
494             The others fields in the dictionaries (other than id and amount) are those of the first tax with a particular id.
495         """
496         taxes_summed = {}
497         for tax in taxes:
498             key = (tax['type'], tax['id'])
499             if key in taxes_summed:
500                 taxes_summed[key]['amount'] += tax['amount']
501             else:
502                 taxes_summed[key] = tax
503         return taxes_summed.values()
504
505     def compute_buyer_costs(self, cr, uid, ids):
506         amount_total = {}
507         lots = self.browse(cr, uid, ids)
508 ##CHECKME: est-ce que ca vaudrait la peine de faire des groupes de lots qui ont les memes couts pour passer des listes de lots a compute?
509         taxes = []
510         amount=0.0
511     #   pt_tax=pool.get('account.tax')
512         for lot in lots:
513             taxes = lot.product_id.taxes_id
514             if lot.author_right:
515                 taxes.append(lot.author_right)
516             elif lot.auction_id:
517                 taxes += lot.auction_id.buyer_costs
518             tax=self.pool.get('account.tax').compute(cr,uid,taxes,lot.obj_price,1)
519             for t in tax:
520                 amount+=t['amount']
521             #amount+=lot.obj_price*0.2
522             #amount+=lot.obj_price
523         amount_total['value']= amount
524         amount_total['amount']= amount
525         return amount_total
526
527
528
529 #       for t in taxes_res:
530 #           t.update({'type': 0})
531 #       return self._sum_taxes_by_type_and_id(taxes_res)
532
533 #   lots=self.browse(cr,uid,ids)
534 #   amount=0.0
535 #   for lot in lots:
536 #       taxes=lot.product_id.taxe_id
537
538
539     def _compute_lot_seller_costs(self, cr, uid, lot, manual_only=False):
540         costs = []
541         tax_cost_ids=[]
542 #       tax_cost_ids = [i.id for i in lot.auction_id.seller_costs]
543         # if there is a specific deposit cost for this depositer, add it
544         border_id = lot.bord_vnd_id
545         if border_id:
546             if border_id.tax_id:
547                 tax_cost_ids.append(border_id.tax_id)
548             elif lot.auction_id and lot.auction_id.seller_costs:
549                 tax_cost_ids += lot.auction_id.seller_costs
550         tax_costs = self.pool.get('account.tax').compute(cr, uid, tax_cost_ids, lot.obj_price, 1)
551         # delete useless keys from the costs computed by the tax object... this is useless but cleaner...
552         for cost in tax_costs:
553             del cost['account_paid_id']
554             del cost['account_collected_id']
555
556         if not manual_only:
557             costs.extend(tax_costs)
558             for c in costs:
559                 c.update({'type': 0})
560 ######
561         if lot.vnd_lim_net<0 and lot.obj_price>0:
562 #FIXME: la string 'remise lot' devrait passer par le systeme de traductions
563             obj_price_wh_costs = reduce(lambda x, y: x + y['amount'], tax_costs, lot.obj_price)
564             if obj_price_wh_costs < lot.vnd_lim:
565                 costs.append({  'type': 1,
566                                 'id': lot.obj_num,
567                                 'name': 'Remise lot '+ str(lot.obj_num),
568                                 'amount': lot.vnd_lim - obj_price_wh_costs}
569                                 #'account_id': lot.auction_id.acc_refund.id
570                             )
571         return costs
572     def compute_seller_costs(self, cr, uid, ids, manual_only=False):
573         lots = self.browse(cr, uid, ids)
574         costs = []
575
576         # group objects (lots) by deposit id
577         # ie create a dictionary containing lists of objects
578         bord_lots = {}
579         for lot in lots:
580             key = lot.bord_vnd_id.id
581             if not key in bord_lots:
582                 bord_lots[key] = []
583             bord_lots[key].append(lot)
584
585         # use each list of object in turn
586         for lots in bord_lots.values():
587             total_adj = 0
588             total_cost = 0
589             for lot in lots:
590                 total_adj += lot.obj_price or 0.0
591                 lot_costs = self._compute_lot_seller_costs(cr, uid, lot, manual_only)
592                 for c in lot_costs:
593                     total_cost += c['amount']
594                 costs.extend(lot_costs)
595             bord = lots[0].bord_vnd_id
596             if bord:
597                 if bord.specific_cost_ids:
598                     bord_costs = [{'type':2, 'id':c.id, 'name':c.name, 'amount':c.amount, 'account_id':c.account} for c in bord.specific_cost_ids]
599                     for c in bord_costs:
600                         total_cost += c['amount']
601                     costs.extend(bord_costs)
602             if (total_adj+total_cost)<0:
603 #FIXME: translate tax name
604                 new_id = bord and bord.id or 0
605                 c = {'type':3, 'id':new_id, 'amount':-total_cost-total_adj, 'name':'Ristourne'}#, 'account_id':lots[0].auction_id.acc_refund.id}
606                 costs.append(c)
607         return self._sum_taxes_by_type_and_id(costs)
608
609     # sum remise limite net and ristourne
610     def compute_seller_costs_summed(self, cr, uid, ids): #ach_pay_id
611         taxes = self.compute_seller_costs(cr, uid, ids)
612         taxes_summed = {}
613         for tax in taxes:
614             if tax['type'] == 1:
615                 tax['id'] = 0
616     #FIXME: translate tax names
617                 tax['name'] = 'Remise limite nette'
618             elif tax['type'] == 2:
619                 tax['id'] = 0
620                 tax['name'] = 'Frais divers'
621             elif tax['type'] == 3:
622                 tax['id'] = 0
623                 tax['name'] = 'Rist.'
624             key = (tax['type'], tax['id'])
625             if key in taxes_summed:
626                 taxes_summed[key]['amount'] += tax['amount']
627             else:
628                 taxes_summed[key] = tax
629         return taxes_summed.values()
630
631     def buyer_proforma(self,cr,uid,ids,context):
632         invoices = {}
633         inv_ref=self.pool.get('account.invoice')
634 #       acc_receiv=self.pool.get('account.account').search([cr,uid,[('code','=','4010')]])
635         for lot in self.browse(cr,uid,ids,context):
636             if not lot.obj_price>0:
637                 continue
638             partner_r=self.pool.get('res.partner')
639             if not lot.ach_uid.id:
640                 raise orm.except_orm('Missed buyer !', 'The object "%s" has no buyer assigned.' % (lot.name,))
641             else:
642                 partner_ref =lot.ach_uid.id
643                 lot_name = lot.obj_num
644                 res = self.pool.get('res.partner').address_get(cr, uid, [partner_ref], ['contact', 'invoice'])
645                 contact_addr_id = res['contact']
646                 invoice_addr_id = res['invoice']
647                 inv = {
648                     'name': 'Auction proforma:' +lot.name,
649                     'journal_id': lot.auction_id.journal_id.id,
650                     'partner_id': partner_ref,
651                     'type': 'out_invoice',
652                 #   'state':'proforma',
653                 }
654                 inv.update(inv_ref.onchange_partner_id(cr,uid, [], 'out_invoice', partner_ref)['value'])
655                 inv['account_id'] = inv['account_id'] and inv['account_id'][0]
656                 inv_id = inv_ref.create(cr, uid, inv, context)
657                 invoices[partner_ref] = inv_id
658                 self.write(cr,uid,[lot.id],{'ach_inv_id':inv_id,'state':'sold'})
659
660                 #calcul des taxes
661                 taxes = map(lambda x: x.id, lot.product_id.taxes_id)
662                 taxes+=map(lambda x:x.id, lot.auction_id.buyer_costs)
663                 if lot.author_right:
664                     taxes.append(lot.author_right.id)
665
666                 inv_line= {
667                     'invoice_id': inv_id,
668                     'quantity': 1,
669                     'product_id': lot.product_id.id,
670                     'name': 'proforma'+'['+str(lot.obj_num)+'] '+ lot.name,
671                     'invoice_line_tax_id': [(6,0,taxes)],
672                     'account_analytic_id': lot.auction_id.account_analytic_id.id,
673                     'account_id': lot.auction_id.acc_income.id,
674                     'price_unit': lot.obj_price,
675                 }
676                 self.pool.get('account.invoice.line').create(cr, uid, inv_line,context)
677             #   inv_ref.button_compute(cr, uid, [inv_id])
678             #   wf_service = netsvc.LocalService('workflow')
679             #   wf_service.trg_validate(uid, 'account.invoice', inv_id, 'invoice_open', cr)
680             inv_ref.button_compute(cr, uid, invoice.values())
681             wf_service = netsvc.LocalService('workflow')
682             wf_service.trg_validate(uid, 'account.invoice', inv_id, 'invoice_proforma', cr)
683         return invoices.values()
684
685
686     # creates the transactions between the auction company and the seller
687     # this is done by creating a new in_invoice for each
688     def seller_trans_create(self,cr, uid,ids,context):
689         """
690             Create a seller invoice for each bord_vnd_id, for selected ids.
691         """
692         # use each list of object in turn
693         invoices = {}
694         inv_ref=self.pool.get('account.invoice')
695         for lot in self.browse(cr,uid,ids,context):
696             partner_id = lot.bord_vnd_id.partner_id.id
697             if not lot.auction_id.id:
698                 continue
699             lot_name = lot.obj_num
700             if lot.bord_vnd_id.id in invoices:
701                 inv_id = invoices[lot.bord_vnd_id.id]
702             else:
703                 res = self.pool.get('res.partner').address_get(cr, uid, [lot.bord_vnd_id.partner_id.id], ['contact', 'invoice'])
704                 contact_addr_id = res['contact']
705                 invoice_addr_id = res['invoice']
706                 inv = {
707                     'name': 'Auction:' +lot.name,
708                     'journal_id': lot.auction_id.journal_seller_id.id,
709                     'partner_id': lot.bord_vnd_id.partner_id.id,
710                     'type': 'in_invoice',
711                 }
712                 inv.update(inv_ref.onchange_partner_id(cr,uid, [], 'in_invoice', lot.bord_vnd_id.partner_id.id)['value'])
713             #   inv['account_id'] = inv['account_id'] and inv['account_id'][0]
714                 inv_id = inv_ref.create(cr, uid, inv, context)
715                 invoices[lot.bord_vnd_id.id] = inv_id
716
717             self.write(cr,uid,[lot.id],{'sel_inv_id':inv_id,'state':'sold'})
718
719             taxes = map(lambda x: x.id, lot.product_id.taxes_id)
720             if lot.bord_vnd_id.tax_id:
721                 taxes.append(lot.bord_vnd_id.tax_id.id)
722             else:
723                 taxes += map(lambda x: x.id, lot.auction_id.seller_costs)
724
725             inv_line= {
726                 'invoice_id': inv_id,
727                 'quantity': 1,
728                 'product_id': lot.product_id.id,
729                 'name': '['+str(lot.obj_num)+'] '+lot.auction_id.name,
730                 'invoice_line_tax_id': [(6,0,taxes)],
731                 'account_analytic_id': lot.auction_id.account_analytic_id.id,
732                 'account_id': lot.auction_id.acc_expense.id,
733                 'price_unit': lot.obj_price,
734             }
735             self.pool.get('account.invoice.line').create(cr, uid, inv_line,context)
736             inv_ref.button_compute(cr, uid, invoices.values())
737         for inv in inv_ref.browse(cr, uid, invoices.values(), context):
738             inv_ref.write(cr, uid, [inv.id], {
739                 'check_total': inv.amount_total
740             })
741             wf_service = netsvc.LocalService('workflow')
742             wf_service.trg_validate(uid, 'account.invoice', inv.id, 'invoice_open', cr)
743         return invoices.values()
744
745     def lots_invoice(self, cr, uid, ids, context,invoice_number=False):
746         """(buyer invoice
747             Create an invoice for selected lots (IDS) to BUYER_ID.
748             Set created invoice to the ACTION state.
749             PRE:
750                 ACTION:
751                     False: no action
752                     xxxxx: set the invoice state to ACTION
753
754             RETURN: id of generated invoice
755         """
756         dt = time.strftime('%Y-%m-%d')
757         inv_ref=self.pool.get('account.invoice')
758         invoices={}
759         print "KKKKKKKKKKKKKKKKK"
760         for lot in self.browse(cr, uid, ids,context):
761             print "LLLLLLLLLLLLLLLL"
762         #   partner_ref = lot.ach_uid.id
763             if not lot.auction_id.id:
764                 continue
765             partner_r=self.pool.get('res.partner')
766             if not lot.ach_uid.id:
767                 raise orm.except_orm('Missed buyer !', 'The object "%s" has no buyer assigned.' % (lot.name,))
768             if (lot.auction_id.id,lot.ach_uid.id) in invoices:
769                 inv_id = invoices[(lot.auction_id.id,lot.ach_uid.id)]
770             else:
771                 price = lot.obj_price or 0.0
772                 lot_name =lot.obj_num
773                 inv={
774                     'name':lot.auction_id.name or '',
775                     'reference': lot.ach_login,
776                     'journal_id': lot.auction_id.journal_id.id,
777                     'partner_id': lot.ach_uid.id,
778                     'type': 'out_invoice',
779                 }
780                 if invoice_number:
781                     inv['number'] = invoice_number
782                 inv.update(inv_ref.onchange_partner_id(cr,uid, [], 'out_invoice', lot.ach_uid.id)['value'])
783                 #inv['account_id'] = inv['account_id'] and inv['account_id'][0]
784                 inv_id = inv_ref.create(cr, uid, inv, context)
785                 print "IN>>>>>>>>>>>>ID",inv_id
786                 invoices[(lot.auction_id.id,lot.ach_uid.id)] = inv_id
787             self.write(cr,uid,[lot.id],{'ach_inv_id':inv_id,'state':'sold'})
788             #calcul des taxes
789             taxes = map(lambda x: x.id, lot.product_id.taxes_id)
790             taxes+=map(lambda x:x.id, lot.auction_id.buyer_costs)
791             if lot.author_right:
792                 taxes.append(lot.author_right.id)
793
794             inv_line= {
795                 'invoice_id': inv_id,
796                 'quantity': 1,
797                 'product_id': lot.product_id.id,
798                 'name': '['+str(lot.obj_num)+'] '+ lot.name,
799                 'invoice_line_tax_id': [(6,0,taxes)],
800                 'account_analytic_id': lot.auction_id.account_analytic_id.id,
801                 'account_id': lot.auction_id.acc_income.id,
802                 'price_unit': lot.obj_price,
803             }
804             self.pool.get('account.invoice.line').create(cr, uid, inv_line,context)
805     #   inv_ref.button_compute(cr, uid, [inpq tu dis cav_id])
806     #       inv_ref.button_compute(cr, uid, [inv_id])
807             inv_ref.button_compute(cr, uid, [inv_id])
808         for l in  inv_ref.browse(cr, uid, invoices.values(), context):
809             wf_service = netsvc.LocalService('workflow')
810         #   wf_service.trg_validate(uid, 'account.invoice',l.id, 'invoice_proforma', cr)
811             wf_service.trg_validate(uid, 'account.invoice',l.id, 'invoice_open', cr)
812         return invoices.values()
813
814
815     def numerotate(self, cr, uid, ids):
816         cr.execute('select auction_id from auction_lots where id=%d', (ids[0],))
817         auc_id = cr.fetchone()[0]
818         cr.execute('select max(obj_num) from auction_lots where auction_id=%d', (auc_id,))
819         try:
820             max = cr.fetchone()[0]
821         except:
822             max = 0
823         for id in ids:
824             max+=1
825             cr.execute('update auction_lots set obj_num=%d where id=%d', (max, id))
826         return []
827
828 auction_lots()
829
830 #----------------------------------------------------------
831 # Auction Bids
832 #----------------------------------------------------------
833 class auction_bid(osv.osv):
834     _name = "auction.bid"
835     _description="Bid auctions"
836     _order = 'id desc'
837     _columns = {
838         'partner_id': fields.many2one('res.partner', 'Buyer Name', required=True),
839         'contact_tel':fields.char('Contact',size=64),
840         'name': fields.char('Bid ID', size=64,required=True),
841         'auction_id': fields.many2one('auction.dates', 'Auction Date', required=True),
842         'bid_lines': fields.one2many('auction.bid_line', 'bid_id', 'Bid'),
843     }
844     _defaults = {
845         'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'auction.bid'),
846     }
847     def onchange_contact(self, cr, uid, ids, partner_id):
848         if not partner_id:
849             return {'value': {'contact_tel':False}}
850         contact = self.pool.get('res.partner').browse(cr, uid, partner_id)
851         v_contact=contact.address[0] and contact.address[0].phone or False
852         return {'value': {'contact_tel': v_contact}}
853
854 auction_bid()
855
856 class auction_lot_history(osv.osv):
857     _name = "auction.lot.history"
858     _description="Lot history"
859     _columns = {
860         'name': fields.date('Date',size=64),
861         'lot_id': fields.many2one('auction.lots','Object', required=True, ondelete='cascade'),
862         'auction_id': fields.many2one('auction.dates', 'Auction date', required=True, ondelete='cascade'),
863         'price': fields.float('Withdrawn price', digits=(16,2))
864     }
865     _defaults = {
866         'name': lambda *args: time.strftime('%Y-%m-%d')
867     }
868 auction_lot_history()
869
870 class auction_bid_lines(osv.osv):
871     _name = "auction.bid_line"
872     _description="Bid"
873
874 #   def get_nom(self,cr,uid,ids,*a):
875 #       res = {}
876 #       lots=self.browse(cr,uid,ids)
877 #       for lot in lots:
878 #           res[lot.id] = lot.lot_id.auction_id.name
879 #           print lot.lot_id.auction_id.name
880 #       return res
881     _columns = {
882         'name': fields.char('Bid date',size=64),
883         'bid_id': fields.many2one('auction.bid','Bid ID', required=True, ondelete='cascade'),
884         'lot_id': fields.many2one('auction.lots','Object', required=True, ondelete='cascade'),
885         'call': fields.boolean('To be Called'),
886         'price': fields.float('Maximum Price'),
887         'auction': fields.char(string='Auction Name', size=64)
888     }
889     _defaults = {
890         'name': lambda *args: time.strftime('%Y-%m-%d')
891     }
892
893     def onchange_name(self, cr, uid, ids, lot_id):
894         if not lot_id:
895             return {'value': {'auction':False}}
896         auctions = self.pool.get('auction.lots').browse(cr, uid, lot_id)
897         v_auction=auctions.auction_id.name or False
898         return {'value': {'auction': v_auction}}
899
900
901 auction_bid_lines()
902
903 class report_buyer_auction(osv.osv):
904     _name = "report.buyer.auction"
905     _description = "Auction Reporting on buyer view"
906     _auto = False
907     _columns = {
908         'buyer_login': fields.char('Buyer Login',size=64, readonly=True, select=1),
909         'buyer':fields.many2one('res.partner', 'Buyer', readonly=True, select=2),
910         'object':fields.integer('No of objects',readonly=True, select=1),
911         'total_price':fields.float('Total Adj.', digits=(16,2), readonly=True, select=2),
912         'avg_price':fields.float('Avg Adj.', digits=(16,2), readonly=True, select=2),
913         'date': fields.date('Create Date',  select=1),
914         'auction': fields.many2one('auction.dates', 'Auction date',readonly=True, select=1),
915
916     }
917
918     def init(self, cr):
919         cr.execute('''
920         create or replace view report_buyer_auction  as (
921             select
922                 min(al.id) as id,
923                 al.ach_login as "buyer_login",
924                 to_char(al.create_date, 'YYYY-MM-01') as date,
925                 al.ach_uid as "buyer",
926                 ad.id as auction,
927                 count(al.id) as "object",
928                 sum(al.obj_price) as "total_price",
929                 (sum(al.obj_price)/count(al.id)) as "avg_price"
930             from
931                 auction_lots al,
932                 auction_dates ad
933             where
934                 ad.id=al.auction_id
935             group by
936                 to_char(al.create_date, 'YYYY-MM-01'),
937                 al.ach_uid,
938                 ad.id,
939                 al.ach_login
940         )''')
941 report_buyer_auction()
942
943 class report_buyer_auction2(osv.osv):
944     _name = "report.buyer.auction2"
945     _description = "Auction Reporting on buyer view"
946     _auto = False
947     _columns = {
948         'auction': fields.many2one('auction.dates', 'Auction date',readonly=True, select=1),
949         'buyer_login': fields.char('Buyer Login',size=64, readonly=True, select=True),
950         'buyer':fields.many2one('res.partner', 'Buyer', readonly=True, select=2),
951         'sumadj':fields.float('Sum of adjustication',readonly=True),
952         'gross_revenue':fields.float('Gross Revenue', readonly=True),
953         'net_revenue':fields.float('Net Revenue', readonly=True),
954         'net_margin':fields.float('Net Margin', readonly=True),
955         'date': fields.date('Create Date',  required=True)
956     }
957     def init(self, cr):
958         cr.execute('''
959             create or replace view report_buyer_auction2  as (
960                 select
961                     min(al.id) as id,
962                     to_char(al.create_date, 'YYYY-MM-01') as date,
963                     al.ach_login as "buyer_login",
964                     al.ach_uid as "buyer",
965                     sum(al.obj_price) as sumadj,
966                     ad.id as auction,
967                     sum(al.gross_revenue) as gross_revenue,
968                     sum(al.net_revenue) as net_revenue,
969                     avg(al.net_margin) as net_margin
970                 from
971                     auction_lots al,
972                     auction_dates ad
973                 where
974                     al.auction_id=ad.id
975                 group by
976                     al.ach_uid,
977                     al.ach_login,
978                     ad.id,
979                     to_char(al.create_date, 'YYYY-MM-01')
980             )''')
981 report_buyer_auction2()
982
983
984 class report_seller_auction(osv.osv):
985     _name = "report.seller.auction"
986     _description = "Auction Reporting on seller view"
987     _auto = False
988     _rec_name = 'date'
989     _columns = {
990         'auction': fields.many2one('auction.dates', 'Auction date',readonly=True, select=1),
991         'seller': fields.many2one('res.partner','Seller',readonly=True, select=1),
992         'object_number':fields.integer('No of Objects',readonly=True),
993         'total_price':fields.float('Total adjudication',readonly=True),
994         'avg_price':fields.float('Avg adjudication',readonly=True),
995         'avg_estimation':fields.float('Avg estimation',readonly=True),
996         'date': fields.date('Create Date',  required=True, select=1),
997         'state': fields.selection((('draft','Draft'),('unsold','Unsold'),('sold','Sold')),'Status',readonly=True, select=1)
998     }
999
1000     def init(self, cr):
1001         cr.execute('''
1002             create or replace view report_seller_auction  as (
1003                 select
1004                     adl.id as auction,
1005                     min(al.id) as id,
1006                     adl.auction1 as date,
1007                     ad.partner_id as seller,
1008                     count(al.id) as "object_number",
1009                     SUM(al.obj_price) as "total_price",
1010                     (SUM(al.obj_price)/count(al.id)) as avg_price,
1011                     sum(al.lot_est1+al.lot_est2)/2 as avg_estimation,
1012                     al.state
1013                 from
1014                     auction_dates adl,
1015                     auction_lots al,
1016                     auction_deposit ad
1017                 where
1018                     al.auction_id=adl.id and ad.id=al.bord_vnd_id
1019                 group by
1020                     ad.partner_id,
1021                     al.state,adl.auction1,adl.id
1022                 )''')
1023 report_seller_auction()
1024
1025 class report_seller_auction2(osv.osv):
1026     _name = "report.seller.auction2"
1027     _description = "Auction Reporting on seller view2"
1028     _auto = False
1029     _columns = {
1030         'seller': fields.many2one('res.partner','Seller',readonly=True, select=1),
1031         'auction': fields.many2one('auction.dates', 'Auction date',readonly=True, select=1),
1032         'sum_adj':fields.float('Sum Adjustication',readonly=True, select=2),
1033         'gross_revenue':fields.float('Gross revenue',readonly=True, select=2),
1034         'net_revenue':fields.float('Net revenue',readonly=True, select=2),
1035         'net_margin':fields.float('Net margin', readonly=True, select=2),
1036         'date': fields.date('Auction date',  required=1),
1037     }
1038
1039     def init(self, cr):
1040         cr.execute('''create or replace view report_seller_auction2  as
1041             (select
1042                 min(al.id) as id,
1043                 adl.auction1 as date,
1044                 adl.id as auction,
1045                 ad.partner_id as seller,
1046                 sum(al.obj_price) as "sum_adj",
1047                 sum(al.gross_revenue) as "gross_revenue",
1048                 sum(al.net_revenue) as "net_revenue",
1049                 avg(al.net_margin) as "net_margin"
1050             from
1051                 auction_lots al,auction_dates adl,auction_deposit ad
1052             where
1053                 adl.id=al.auction_id and ad.id=al.bord_vnd_id
1054             group by
1055                 al.ach_uid,adl.auction1,adl.id,ad.partner_id)
1056              ''')
1057
1058 report_seller_auction2()
1059
1060 class report_auction_view2(osv.osv):
1061     _name = "report.auction.view2"
1062     _description = "Auction Reporting on  view2"
1063     _auto = False
1064     _rec_name = 'date'
1065     _columns = {
1066         'auction': fields.many2one('auction.dates', 'Auction date',readonly=True, select=1),
1067         'sum_adj':fields.float('Sum of adjudication',readonly=True),
1068         'obj_number':fields.integer('# of Objects',readonly=True),
1069         'gross_revenue':fields.float('Gross revenue',readonly=True),
1070         'net_revenue':fields.float('Net revenue',readonly=True),
1071         'obj_margin':fields.float('Avg margin', readonly=True),
1072         'obj_margin_procent':fields.float('Net margin (%)', readonly=True),
1073         'date': fields.date('Auction date',  required=True, select=1)
1074     }
1075     def init(self, cr):
1076         cr.execute('''create or replace view report_auction_view2 as (
1077             select
1078                 ad.id as id,
1079                 ad.auction1 as date,
1080                 ad.id as "auction",
1081                 count(al.id) as "obj_number",
1082                 SUM(al.obj_price) as "sum_adj",
1083                 SUM(al.gross_revenue) as "gross_revenue",
1084                 SUM(al.net_revenue) as "net_revenue",
1085                 avg(al.net_revenue) as "obj_margin",
1086                 SUM(al.net_revenue)*100/sum(al.obj_price) as "obj_margin_procent"
1087             from
1088                 auction_dates ad
1089             left join
1090                 auction_lots al on (al.auction_id = ad.id)
1091             group by
1092                 ad.id, ad.auction1
1093             having
1094                 sum(al.obj_price) <> 0
1095             )''')
1096 report_auction_view2()
1097
1098 class report_auction_view(osv.osv):
1099     _name = "report.auction.view"
1100     _description = "Auction Reporting on view1"
1101     _auto = False
1102     _rec_name = 'auction_id'
1103     _columns = {
1104         'auction_id': fields.many2one('auction.dates', 'Auction date',readonly=True, select=1),
1105         'nobjects':fields.float('No of objects',readonly=True),
1106         'nbuyer':fields.float('No of buyers',readonly=True),
1107         'nseller':fields.float('No of sellers',readonly=True),
1108         'min_est':fields.float('Minimum Estimation', readonly=True, select=2),
1109         'max_est':fields.float('Maximum Estimation', readonly=True, select=2),
1110         'adj_price':fields.float('Adjudication price', readonly=True, select=2),
1111         'obj_ret':fields.integer('# obj ret', readonly=True, select=2)
1112     }
1113
1114     def init(self, cr):
1115         cr.execute('''create or replace view report_auction_view  as
1116             (select
1117                 min(al.id) as id,
1118                 al.auction_id as "auction_id",
1119                 count(al.id) as "nobjects",
1120                 count(al.ach_login) as "nbuyer",
1121                 count(al.bord_vnd_id) as "nseller",
1122                 sum(al.lot_est1) as "min_est",
1123                 sum(al.lot_est2) as "max_est",
1124                 (SELECT count(1) FROM auction_lots WHERE obj_ret>0) as obj_ret,
1125                 sum(al.obj_price) as "adj_price"
1126             from
1127                 auction_lots al
1128             group by
1129                 al.auction_id
1130         )''')
1131
1132 report_auction_view()
1133
1134 class report_auction_object_date(osv.osv):
1135     _name = "report.auction.object.date"
1136     _description = "Objects per day"
1137     _auto = False
1138     _columns = {
1139         'obj_num': fields.integer('# of Objects'),
1140         'name': fields.date('Created date', select=2),
1141         'month': fields.date('Month', select=1),
1142         'user_id':fields.many2one('res.users', 'User',select=1),
1143     }
1144  #l.create_uid as user,
1145
1146     def init(self, cr):
1147         cr.execute("""create or replace view report_auction_object_date as
1148             (select
1149                min(l.id) as id,
1150                to_char(l.create_date, 'YYYY-MM-DD') as name,
1151                to_char(l.create_date, 'YYYY-MM-01') as month,
1152                count(l.obj_num) as obj_num,
1153                l.create_uid as user_id
1154             from
1155                 auction_lots l
1156             group by
1157                 to_char(l.create_date, 'YYYY-MM-DD'),
1158                 to_char(l.create_date, 'YYYY-MM-01'),
1159                 l.create_uid
1160             )
1161         """)
1162 report_auction_object_date()
1163
1164 class report_auction_estimation_adj_category(osv.osv):
1165     _name = "report.auction.estimation.adj.category"
1166     _description = "comparaison estimate/adjudication "
1167     _auto = False
1168     _rec_name='date'
1169     _columns = {
1170             'lot_est1': fields.float('Minimum Estimation',select=2),
1171             'lot_est2': fields.float('Maximum Estimation',select=2),
1172             'obj_price': fields.float('Adjudication price'),
1173             'date': fields.date('Date', readonly=True,select=1),
1174             'lot_type': fields.selection(_type_get, 'Object Type', size=64),
1175             'adj_total': fields.float('Total Adjudication',select=2),
1176             'user_id':fields.many2one('res.users', 'User', select=1)
1177     }
1178
1179     def init(self, cr):
1180         cr.execute("""
1181             create or replace view report_auction_estimation_adj_category as (
1182                 select
1183                    min(l.id) as id,
1184                    to_char(l.create_date, 'YYYY-MM-01') as date,
1185                    l.lot_type as lot_type,
1186                    sum(l.lot_est1) as lot_est1,
1187                    sum(l.lot_est2) as lot_est2,
1188                    sum(l.obj_price) as adj_total,
1189                    l.create_uid as user_id
1190                 from
1191                     auction_lots l,auction_dates m
1192                 where
1193                     l.auction_id=m.id and l.obj_price >0
1194                 group by
1195                      to_char(l.create_date, 'YYYY-MM-01'),lot_type,l.create_uid
1196             )
1197         """)
1198 report_auction_estimation_adj_category()
1199
1200 class report_auction_adjudication(osv.osv):
1201     _name = "report.auction.adjudication"
1202     _description = "report_auction_adjudication"
1203     _auto = False
1204     _columns = {
1205             'name': fields.many2one('auction.dates','Auction date',readonly=True,select=1),
1206             'state': fields.selection((('draft','Draft'),('close','Closed')),'Status', select=1),
1207             'adj_total': fields.float('Total Adjudication'),
1208             'date': fields.date('Date', readonly=True,select=1),
1209             'user_id':fields.many2one('res.users', 'User',select=1)
1210
1211     }
1212
1213
1214     def init(self, cr):
1215         cr.execute("""
1216             create or replace view report_auction_adjudication as (
1217                 select
1218                     l.id as id,
1219                     l.id as name,
1220                     sum(m.obj_price) as adj_total,
1221                     to_char(l.create_date, 'YYYY-MM-01') as date,
1222                     l.create_uid as user_id,
1223                     l.state
1224                 from
1225                     auction_dates l ,auction_lots m
1226                     where
1227                         m.auction_id=l.id
1228                     group by
1229                         l.id,l.state,l.name,l.create_uid,to_char(l.create_date, 'YYYY-MM-01')
1230
1231             )
1232         """)
1233 report_auction_adjudication()
1234
1235 class report_attendance(osv.osv):
1236     _name="report.attendance"
1237     _description = "Report Sign In/Out"
1238     _auto = False
1239     #_rec_name='date'
1240     _columns = {
1241         'name': fields.date('Date', readonly=True,select=1),
1242         'employee_id' : fields.many2one('hr.employee', 'Employee', select=1, readonly=True),
1243         'total_attendance': fields.float('Total', readonly=True),
1244 }
1245     def init(self, cr):
1246         cr.execute("""CREATE OR REPLACE VIEW report_attendance AS
1247             SELECT
1248                 id,
1249                 name,
1250                 employee_id,
1251                 CASE WHEN SUM(total_attendance) < 0
1252                     THEN (SUM(total_attendance) +
1253                         CASE WHEN current_date <> name
1254                             THEN 1440
1255                             ELSE (EXTRACT(hour FROM current_time) * 60) + EXTRACT(minute FROM current_time)
1256                         END
1257                         )
1258                     ELSE SUM(total_attendance)
1259                 END /60  as total_attendance
1260             FROM (
1261                 SELECT
1262                     max(a.id) as id,
1263                     a.name::date as name,
1264                     a.employee_id,
1265                     SUM(((EXTRACT(hour FROM a.name) * 60) + EXTRACT(minute FROM a.name)) * (CASE WHEN a.action = 'sign_in' THEN -1 ELSE 1 END)) as total_attendance
1266                 FROM hr_attendance a
1267                 where name > current_date + interval '-1 day'
1268                 GROUP BY a.name::date, a.employee_id
1269             ) AS fs
1270             GROUP BY name,fs.id,employee_id
1271             """)
1272
1273 report_attendance()
1274
1275
1276 class report_deposit_border(osv.osv):
1277     _name="report.deposit.border"
1278     _description = "Report deposit border"
1279     _auto = False
1280     _rec_name='bord'
1281     _columns = {
1282         'bord': fields.char('Depositer Inventory', size=64, required=True),
1283         'seller': fields.many2one('res.partner','Seller',select=1),
1284         'moy_est' : fields.float('Avg. Est', select=1, readonly=True),
1285         'total_marge': fields.float('Total margin', readonly=True),
1286         'nb_obj':fields.float('# of objects', readonly=True),
1287 }
1288     def init(self, cr):
1289         cr.execute("""CREATE OR REPLACE VIEW report_deposit_border AS
1290             SELECT
1291                 min(al.id) as id,
1292                 ab.partner_id as seller,
1293                 ab.name as bord,
1294                 COUNT(al.id) as nb_obj,
1295                 SUM((al.lot_est1 + al.lot_est2)/2) as moy_est,
1296                 SUM(al.net_revenue)/(count(ad.id)) as total_marge
1297
1298             FROM
1299                 auction_lots al,auction_deposit ab,auction_dates ad
1300             WHERE
1301                 ad.id=al.auction_id
1302                 and al.bord_vnd_id=ab.id
1303             GROUP BY
1304                 ab.name,ab.partner_id""")
1305 report_deposit_border()
1306
1307 class report_object_encoded(osv.osv):
1308     _name = "report.object.encoded"
1309     _description = "Object encoded"
1310     _auto = False
1311     _columns = {
1312         'state': fields.selection((('draft','Draft'),('unsold','Unsold'),('paid','Paid'),('invoiced','Invoiced')),'Status', required=True,select=1),
1313         'user_id':fields.many2one('res.users', 'User', select=1),
1314         'estimation': fields.float('Estimation',select=2),
1315         'date': fields.date('Create Date',  required=True),
1316         'gross_revenue':fields.float('Gross revenue',readonly=True, select=2),
1317         'net_revenue':fields.float('Net revenue',readonly=True, select=2),
1318         'obj_margin':fields.float('Net margin', readonly=True, select=2),
1319         'obj_ret':fields.integer('# obj ret', readonly=True, select=2),
1320         'adj':fields.integer('Adj.', readonly=True, select=2),
1321         'obj_num':fields.integer('# of Encoded obj.', readonly=True, select=2),
1322     }
1323     def init(self, cr):
1324         cr.execute('''create or replace view report_object_encoded  as
1325             (select min(al.id) as id,
1326                 to_char(al.create_date, 'YYYY-MM-DD') as date,
1327                 al.state as state,
1328                 al.create_uid as user_id,
1329                 (SELECT count(1) FROM auction_lots WHERE obj_ret>0) as obj_ret,
1330                 sum((100* al.lot_est1)/al.obj_price) as estimation,
1331                 COUNT(al.product_id) as obj_num
1332             from auction_lots al
1333             where al.obj_price>0 and state='draft'
1334             group by to_char(al.create_date, 'YYYY-MM-DD'), al.state, al.create_uid)
1335              ''')
1336 report_object_encoded()
1337
1338
1339 class report_object_encoded_manager(osv.osv):
1340     _name = "report.object.encoded.manager"
1341     _description = "Object encoded"
1342     _auto = False
1343     _columns = {
1344         'user_id':fields.many2one('res.users', 'User', select=True),
1345         'estimation': fields.float('Estimation',select=True),
1346         'date': fields.date('Create Date',  required=True),
1347         'gross_revenue':fields.float('Gross revenue',readonly=True, select=True),
1348         'net_revenue':fields.float('Net revenue',readonly=True, select=True),
1349         'obj_margin':fields.float('Net margin', readonly=True, select=True),
1350         'obj_ret':fields.integer('# obj ret', readonly=True, select=True),
1351         'adj':fields.integer('Adj.', readonly=True, select=True),
1352         'obj_num':fields.integer('# of Encoded obj.', readonly=True, select=True),
1353     }
1354     def init(self, cr):
1355         cr.execute('''create or replace view report_object_encoded_manager  as
1356             (select
1357                 min(al.id) as id,
1358                 to_char(al.create_date, 'YYYY-MM-DD') as date,
1359                 al.create_uid as user_id,
1360                 sum((100*lot_est1)/obj_price) as estimation,
1361                 (SELECT count(1) FROM auction_lots WHERE obj_ret>0) as obj_ret,
1362                 SUM(al.gross_revenue) as "gross_revenue",
1363                 SUM(al.net_revenue) as "net_revenue",
1364                 SUM(al.net_revenue)/count(al.id) as "obj_margin",
1365                 COUNT(al.product_id) as obj_num,
1366                 SUM(al.obj_price) as "adj"
1367             from auction_lots al
1368             where al.obj_price>0
1369             group by to_char(al.create_date, 'YYYY-MM-DD'), al.create_uid)
1370              ''')
1371 report_object_encoded_manager()
1372
1373 class report_unclassified_objects(osv.osv):
1374     _name = "report.unclassified.objects"
1375     _description = "Unclassified objects "
1376     _auto = False
1377     _columns = {
1378         'name': fields.char('Short Description',size=64, required=True),
1379         'obj_num': fields.integer('Catalog Number'),
1380         'obj_price': fields.float('Adjudication price'),
1381         'lot_num': fields.integer('List Number', required=True, select=1 ),
1382         'state': fields.selection((('draft','Draft'),('unsold','Unsold'),('paid','Paid'),('sold','Sold')),'Status', required=True, readonly=True),
1383         'obj_comm': fields.boolean('Commission'),
1384         'bord_vnd_id': fields.many2one('auction.deposit', 'Depositer Inventory', required=True),
1385         'ach_login': fields.char('Buyer Username',size=64),
1386         'lot_est1': fields.float('Minimum Estimation'),
1387         'lot_est2': fields.float('Maximum Estimation'),
1388         'lot_type': fields.selection(_type_get, 'Object category', size=64),
1389         'auction': fields.many2one('auction.dates', 'Auction date',readonly=True, select=1),
1390     }
1391     def init(self, cr):
1392         cr.execute("""create or replace view report_unclassified_objects as
1393             (select
1394                 min(al.id) as id,
1395                 al.name as name,
1396                 al.obj_price as obj_price,
1397                 al.obj_num as obj_num,
1398                 al.lot_num as lot_num,
1399                 al.state as state,
1400                 al.obj_comm as obj_comm,
1401                 al.bord_vnd_id as bord_vnd_id,
1402                 al.ach_login as ach_login,
1403                 al.lot_est1 as lot_est1,
1404                 al.lot_est2 as lot_est2,
1405                 al.lot_type as lot_type,
1406                 al.auction_id as auction
1407             from auction_lots al,auction_lot_category ac
1408             where (al.lot_type=ac.name) AND (ac.aie_categ='41') AND (al.auction_id is null)
1409 group by al.obj_price,al.obj_num, al.lot_num, al.state, al.obj_comm,al.bord_vnd_id,al.ach_login,al.lot_est1,al.lot_est2,al.lot_type,al.auction_id,al.name)
1410              """)
1411 report_unclassified_objects()
1412
1413 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1414