diff --git a/folio.py b/folio.py index 59f06df..4bcb91f 100644 --- a/folio.py +++ b/folio.py @@ -121,7 +121,7 @@ class Folio(ModelSQL, ModelView): invoice_line = fields.Many2One('account.invoice.line', 'Invoice Line') to_invoice = fields.Boolean('To Invoice', states={ 'invisible': Bool(Eval('invoice_line')), - }, depends=['invoice_line']) + }, depends=['invoice_line'], help='Mark this checkbox if you want to invoice this item') invoice = fields.Function(fields.Many2One('account.invoice', 'Invoice', depends=['invoice_line']), 'get_invoice') invoice_state = fields.Function(fields.Selection( @@ -635,397 +635,6 @@ class FolioGuest(ModelSQL, ModelView): super(FolioGuest, cls).create(new_values) -class HotelCharge(Workflow, ModelSQL, ModelView): - 'Hotel Charge' - __name__ = 'hotel.charge' - - folio = fields.Many2One('', 'Booking Line', required=True) - service_date = fields.Date('Service Date', select=True, required=True) - product = fields.Many2One('product.product', 'Product', - domain=[('salable', '=', True)], required=True) - quantity = fields.Integer('Quantity', required=True) - invoice_to = fields.Many2One('party.party', 'Invoice To', required=True) - unit_price = fields.Numeric('Unit Price', required=True, digits=(16, 2)) - unit_price_w_tax = fields.Function(fields.Numeric('Unit Price', - digits=(16, 2)), 'get_unit_price_w_tax') - order = fields.Char('Order', select=True) - description = fields.Char('Description', select=True) - state = fields.Selection(INVOICE_STATES, 'State', readonly=True) - state_string = state.translated('state') - invoice_line = fields.Many2One('account.invoice.line', 'Invoice Line', - readonly=True) - amount = fields.Function(fields.Numeric('Amount', - digits=(16, 2)), 'get_amount') - taxed_amount = fields.Function(fields.Numeric('Amount with Tax', - digits=(16, 2)), 'get_taxed_amount') - to_invoice = fields.Boolean('To Invoice', states={ - 'invisible': Bool(Eval('invoice_line')), - }, depends=['invoice_line']) - - @classmethod - def __setup__(cls): - super(HotelCharge, cls).__setup__() - cls._buttons.update({ - 'transfer': { - 'invisible': True, - }, - # 'bill': { - # 'invisible': Eval('invoice_state') is not None, - # }, - }) - - @staticmethod - def default_quantity(): - return 1 - - @staticmethod - def default_to_invoice(): - return True - - @staticmethod - def default_date_service(): - today = Pool().get('ir.date').today() - return today - - def get_amount(self, name=None): - if self.quantity and self.unit_price_w_tax: - return self.quantity * self.unit_price_w_tax - return 0 - - def get_unit_price_w_tax(self, name=None): - Tax = Pool().get('account.tax') - res = self.unit_price or 0 - if self.unit_price: - values = Tax.compute( - self.product.template.customer_taxes_used, - self.unit_price, 1) - if values: - value = values[0] - res = value['base'] + value['amount'] - return res - - def get_taxed_amount(self, name=None): - if self.quantity and self.unit_price: - return self.quantity * self.unit_price - - # def compute_amount_with_tax(line): - # tax_amount = _ZERO - # amount = _ZERO - # if line.taxes: - # tax_list = Tax.compute(line.taxes, line.unit_price or _ZERO, - # line.quantity or 0.0) - # - # tax_amount = sum([t['amount'] for t in tax_list], _ZERO) - # - # if line.unit_price: - # amount = line.unit_price * Decimal(line.quantity) - # return amount + tax_amount - - @classmethod - @ModelView.button - def bill(cls, records): - cls.create_sales(records) - - @classmethod - @ModelView.button_action('hotel.wizard_operation_line_transfer') - def transfer(cls, records): - pass - - @fields.depends('unit_price', 'product') - def on_change_product(self): - if self.product: - self.unit_price = self.product.template.list_price - self.description = self.product.description - -# @classmethod -# def validate(cls, records): -# super(Operation, cls).validate(records) -# for r in records: -# operations = cls.search([ -# ('room', '=', r.room.id), -# ('id', '!=', r.id), -# ('state', '!=', 'cancelled'), -# ('kind', '=', 'occupancy'), -# ['AND', ['OR', -# [ -# ('start_date', '>=', r.start_date), -# ('end_date', '<', r.start_date), -# ], [ -# ('start_date', '>=', r.end_date), -# ('end_date', '<=', r.end_date), -# ] -# ]]]) -# if operations: -# raise AccessError(gettext('hotel.msg_occupied_room', s=r.room.name)) -# -# @classmethod -# def occupancy_rate(cls, start, end): -# pool = Pool() -# today_ = pool.get('ir.date').today() -# after_days = today_ + timedelta(days=3) -# before_days = today_ - timedelta(days=3) -# operations = cls.search([ -# ('state', 'not in', ['closed', 'cancelled']), -# ('start_date', '>=', before_days), -# ('end_date', '<=', after_days), -# ]) -# Room = pool.get('hotel.room') -# Housekeeping = pool.get('hotel.housekeeping') -# housekeepings = Housekeeping.search([ -# ('state', '=', 'maintenance') -# ]) -# room_ids = [] -# for hk in housekeepings: -# room_ids.append(hk.room.id) -# rooms = Room.search([ -# ('id', 'not in', room_ids) -# ]) -# qty_booking = len(operations) -# qty_rooms = len(rooms) -# return qty_booking / qty_rooms -# -# def get_unit_price_w_tax(self, name=None): -# Tax = Pool().get('account.tax') -# res = self.unit_price -# if self.unit_price and self.accommodation and not self.taxes_exception: -# values = Tax.compute( -# self.accommodation.template.customer_taxes_used, -# self.unit_price or _ZERO, 1 -# ) -# if len(values) > 0: -# value = values[0] -# res = value['base'] + value['amount'] -# return round(res, Operation.total_amount.digits[1]) -# -# def get_pending_payment(self, name=None): -# res = _ZERO -# if self.total_amount: -# amount_paid = sum([v.amount_to_pay for v in self.vouchers]) -# res = self.total_amount - amount_paid -# res = round(res, Operation.total_amount.digits[1]) -# return res -# -# def get_total_amount(self, name=None): -# res = [] -# if name == 'total_amount': -# if self.unit_price_w_tax and self.nights_quantity: -# res.append(self.room_amount) -# else: -# if self.unit_price_w_tax and self.nights_quantity: -# res.append(self.room_amount_today) -# -# res.extend([l.amount for l in self.lines if l.amount]) -# if res: -# return round(sum(res), Operation.total_amount.digits[1]) -# return _ZERO -# -# @staticmethod -# def default_kind(): -# return 'occupancy' -# -# @classmethod -# @ModelView.button_action('hotel.wizard_operation_advance_voucher') -# def pay_advance(cls, records): -# pass -# -# @classmethod -# def validate_check_out_date(cls, records): -# Date = Pool().get('ir.date') -# today = Date.today() -# for rec in records: -# if rec.end_date != today: -# return False -# -# def update_housekeeping(self, state): -# pool = Pool() -# Housekeeping = pool.get('hotel.housekeeping') -# Configuration = pool.get('hotel.configuration') -# config = Configuration.get_configuration() -# if not config.cleaning_check_in or not config.cleaning_check_out \ -# or not config.cleaning_occupied: -# raise AccessError(gettext('hotel.msg_missing_cleaning_configuration')) -# if state == 'check_in': -# values = { -# 'availability': 'occupied', -# 'cleaning_type': config.cleaning_occupied.id -# } -# elif state == 'check_out': -# values = { -# 'availability': 'available', -# 'state': 'dirty', -# 'cleaning_type': config.cleaning_check_out.id -# } -# -# housekeepings = Housekeeping.search([ -# ('room', '=', self.room.id) -# ]) -# if not housekeepings: -# raise AccessError(gettext('hotel.msg_missing_configuration_housekeeping_rooms')) -# Housekeeping.write(housekeepings, values) -# -# @classmethod -# def _get_origin(cls): -# return ['hotel.operation.maintenance', 'hotel.folio'] -# -# @classmethod -# def get_origin(cls): -# Model = Pool().get('ir.model') -# models = cls._get_origin() -# models = Model.search([ -# ('model', 'in', models), -# ]) -# return [(None, '')] + [(m.model, m.name) for m in models] -# -# @classmethod -# def get_calendar(cls, args={}): -# Room = Pool().get('hotel.room') -# rooms = Room.search_read([], fields_names=['name', 'code'], -# order=[('code', 'ASC')] -# ) -# resources = [{'id': str(r['id']), 'name': r['name']} for r in rooms] -# -# _date = args.get('date') -# if _date: -# _date = datetime.strptime(_date, 'YYYY-MM-DD') -# else: -# _date = date.today() -# -# start_date = _date - timedelta(days=15) -# end_date = _date + timedelta(days=45) -# operations = cls.search_read([ -# ('start_date', '>=', start_date), -# ('start_date', '<=', end_date), -# ('kind', '=', 'occupancy'), -# ('state', 'in', ['draft', 'check_in', 'check_out', 'finished']), -# ], fields_names=['reference', 'kind', 'party.name', 'start_date', -# 'end_date', 'room', 'room.name', 'accommodation.rec_name', -# 'state', 'origin', 'main_guest.name'] -# ) -# -# events = [] -# for o in operations: -# _state = o['state'] -# if o['kind'] == 'occupancy': -# bg_color = COLOR_BOOKING[_state] -# else: -# bg_color = COLOR_MNT[_state] -# events.append({ -# 'id': o['id'], -# 'resourceId': str(o['room']), -# 'title': o['party.name'] or ' ', -# 'reference': o['reference'], -# 'room': o['room.name'], -# 'accommodation': o['accommodation.rec_name'], -# 'start': str(o['start_date']), -# 'end': str(o['end_date']), -# 'resizable': False, -# 'bgColor': bg_color -# }) -# return [resources, events] -# -# @classmethod -# def validate(cls, operations): -# for op in operations: -# op.check_dates( -# op.start_date, -# op.end_date, -# op.room, -# op, -# ) -# super(Operation, cls).validate(operations) -# -# @classmethod -# def get_available_rooms(cls, start_date, end_date, rooms_ids=[], oper=None): -# """ -# Look for available rooms. -# -# given the date interval, return a list of room ids. -# -# a room is available if it has no operation that overlaps -# with the given date interval. -# -# the optional 'rooms' list is a list of room instance, is an -# additional filter, specifying the ids of the desirable rooms. -# -# the optional 'oper' is an operation object that has to be -# filtered out of the test. it is useful for validating an already -# existing operation. -# """ -# -# if start_date >= end_date: -# raise AccessError(gettext('hotel.msg_invalid_date_range')) -# -# # define the domain of the operations that find a -# # room to be available -# dom = ['AND', ['OR', -# [ -# ('start_date', '>=', start_date), -# ('start_date', '<', end_date), -# ('kind', '=', 'occupancy'), -# ], [ -# ('end_date', '<=', end_date), -# ('end_date', '>', start_date), -# ('kind', '=', 'occupancy'), -# ], [ -# ('start_date', '<=', start_date), -# ('end_date', '>=', end_date), -# ('kind', '=', 'occupancy'), -# ], -# ]] -# ## If oper was specified, do not compare the operations with it -# if oper is not None: -# dom.append(('id', '!=', oper.id)) -# -# if rooms_ids: -# dom.append(('room', 'in', rooms_ids)) -# -# operations = cls.search(dom) -# rooms_not_available_ids = [operation.room.id for operation in operations] -# rooms_available_ids = set(rooms_ids) - set(rooms_not_available_ids) -# return list(rooms_available_ids) -# -# @classmethod -# def check_dates(cls, start_date, end_date, room, operation=None): -# rooms_ids = [room.id] -# available_rooms = cls.get_available_rooms( -# start_date, end_date, rooms_ids, operation -# ) -# if room.id not in available_rooms: -# raise AccessError(gettext('hotel.overlap_operation_line', s=room.name)) -# -# @classmethod -# def get_context_price(cls, sale, product): -# context = {} -# -# context['currency'] = sale.currency.id -# context['customer'] = sale.party.id -# context['price_list'] = sale.price_list.id if sale.price_list else None -# context['uom'] = product.template.default_uom.id -# -# # Set taxes before unit_price to have taxes in context of sale price -# taxes = [] -# pattern = {} -# for tax in product.customer_taxes_used: -# if sale.party and sale.party.customer_tax_rule: -# tax_ids = sale.party.customer_tax_rule.apply(tax, pattern) -# if tax_ids: -# taxes.extend(tax_ids) -# continue -# taxes.append(tax.id) -# if sale.party and sale.party.customer_tax_rule: -# tax_ids = sale.party.customer_tax_rule.apply(None, pattern) -# if tax_ids: -# taxes.extend(tax_ids) -# -# context['taxes'] = taxes -# return context -# -# @classmethod -# def get_taxes(cls, sale, product): -# ctx = cls.get_context_price(sale, product) -# return ctx['taxes'] - - class OperationMaintenance(Workflow, ModelSQL, ModelView): 'Operation Maintenance' __name__ = 'hotel.operation.maintenance' @@ -1174,6 +783,10 @@ class FolioCharge(Workflow, ModelSQL, ModelView): def default_quantity(): return 1 + @staticmethod + def default_to_invoice(): + return True + @staticmethod def default_date_service(): today = Pool().get('ir.date').today() diff --git a/service.py b/service.py index b221b22..1ba18b9 100644 --- a/service.py +++ b/service.py @@ -252,6 +252,7 @@ class ServiceLine(Workflow, ModelSQL, ModelView): 'invoice_to': self.folio.main_guest.id, 'unit_price': self.product.template.list_price, 'product': self.product.id, + 'to_invoice': True, 'state': '', } diff --git a/tryton.cfg b/tryton.cfg index d2eca05..b2cfee6 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=6.0.6 +version=6.0.7 depends: party company