Ir al contenido
Odoo Menú
  • Identificarse
  • Pruébalo gratis
  • Aplicaciones
    Finanzas
    • Contabilidad
    • Facturación
    • Gastos
    • Hoja de cálculo (BI)
    • Documentos
    • Firma electrónica
    Ventas
    • CRM
    • Ventas
    • TPV para tiendas
    • TPV para restaurantes
    • Suscripciones
    • Alquiler
    Sitios web
    • Creador de sitios web
    • Comercio electrónico
    • Blog
    • Foro
    • Chat en directo
    • eLearning
    Cadena de suministro
    • Inventario
    • Fabricación
    • PLM
    • Compra
    • Mantenimiento
    • Calidad
    Recursos Humanos
    • Empleados
    • Reclutamiento
    • Ausencias
    • Evaluación
    • Referencias
    • Flota
    Marketing
    • Marketing social
    • Marketing por correo electrónico
    • Marketing por SMS
    • Eventos
    • Automatización de marketing
    • Encuestas
    Servicios
    • Proyecto
    • Partes de horas
    • Servicio de campo
    • Servicio de asistencia
    • Planificación
    • Citas
    Productividad
    • Conversaciones
    • Aprobaciones
    • IoT
    • VoIP
    • Conocimientos
    • WhatsApp
    Aplicaciones de terceros Studio de Odoo Plataforma de Odoo Cloud
  • Industrias
    Comercio al por menor
    • Librería
    • Tienda de ropa
    • Tienda de muebles
    • Tienda de ultramarinos
    • Ferretería
    • Juguetería
    Alimentación y hostelería
    • Bar y taberna
    • Restaurante
    • Comida rápida
    • Casa de huéspedes
    • Distribuidor de bebidas
    • Hotel
    Inmueble
    • Agencia inmobiliaria
    • Estudio de arquitectura
    • Construcción
    • Gestión inmobiliaria
    • Jardinería
    • Asociación de propietarios
    Consultoría
    • Empresa contable
    • Partner de Odoo
    • Agencia de marketing
    • Bufete de abogados
    • Adquisición de talentos
    • Auditorías y certificaciones
    Fabricación
    • Textil
    • Metal
    • Muebles
    • Alimentos
    • Brewery
    • Regalos de empresas
    Salud y bienestar
    • Club deportivo
    • Óptica
    • Gimnasio
    • Terapeutas
    • Farmacia
    • Peluquería
    Oficios
    • Handyman
    • Hardware y asistencia informática
    • Sistemas de energía solar
    • Zapatero
    • Servicios de limpieza
    • Servicios de calefacción, ventilación y aire acondicionado
    Otros
    • Organización sin ánimo de lucro
    • Agencia de protección del medio ambiente
    • Alquiler de paneles publicitarios
    • Estudio fotográfico
    • Alquiler de bicicletas
    • Distribuidor de software
    Browse all Industries
  • Comunidad
    Aprender
    • Tutoriales
    • Documentación
    • Certificaciones
    • Formación
    • Blog
    • Podcast
    Potenciar la educación
    • Programa de formación
    • Scale Up! El juego empresarial
    • Visita Odoo
    Obtener el software
    • Descargar
    • Comparar ediciones
    • Versiones
    Colaborar
    • GitHub
    • Foro
    • Eventos
    • Traducciones
    • Convertirse en partner
    • Services for Partners
    • Registrar tu empresa contable
    Obtener servicios
    • Encontrar un partner
    • Encontrar un asesor fiscal
    • Contacta con un experto
    • Servicios de implementación
    • Referencias de clientes
    • Ayuda
    • Actualizaciones
    GitHub YouTube Twitter Linkedin Instagram Facebook Spotify
    +1 (650) 691-3277
    Solicitar una demostración
  • Precios
  • Ayuda

Odoo is the world's easiest all-in-one management software.
It includes hundreds of business apps:

  • CRM
  • e-Commerce
  • Contabilidad
  • Inventario
  • PoS
  • Proyecto
  • MRP
All apps
Debe estar registrado para interactuar con la comunidad.
Todas las publicaciones Personas Insignias
Etiquetas (Ver todo)
odoo accounting v14 pos v15
Acerca de este foro
Debe estar registrado para interactuar con la comunidad.
Todas las publicaciones Personas Insignias
Etiquetas (Ver todo)
odoo accounting v14 pos v15
Acerca de este foro
Ayuda

PoS Sale from 2 locations

Suscribirse

Reciba una notificación cuando haya actividad en esta publicación

Se marcó esta pregunta
posinventorypicking
3 Respuestas
6266 Vistas
Avatar
A B

Setup:

  • 2 locations:

    • Retail - Front of house, contains some products

    • Warehouse - contains larger products

  • Odoo CE 10

  • PoS in retail location

Issue:

    When creating a sale from PoS, some items need to be moved from the warehouse to the retail location for the     client. I cannot find a way of automatically generating a (picking?) for this.

    Alternatively:

    Some way of creating a form/report/(picking?) to notify the warehouse of what should be loaded for the client

The issue we are currently facing is that we sell things from the PoS(in retail location), however the stock actually comes from the warehouse. This causes the retail location to have negative stock.

If anyone has any suggestions as to how I can resolve this issue, please let me know.    

0
Avatar
Descartar
Emipro Technologies Pvt. Ltd.

As there are two locations you mentioned, practically / in reality, what exactly are you doing when you suppose to transfer goods from one location / warehouse to another location / warehouse for retail store? If you can describe that, I can suggest you how we can achieve this in Odoo.

Avatar
jithesh
Mejor respuesta

here we design a .py  code to implement custom picking

the user can automattically select stock location and shelf and row the product stocked its not completed it is use-ful to you


import logging
from datetime import timedelta
from functools import partial

import psycopg2
from collections import namedtuple
import json
import time
import ast
from odoo.tools.float_utils import float_compare
from odoo import api, fields, models, tools, _
from odoo.tools import float_is_zero
from odoo.exceptions import UserError
from odoo.http import request
import odoo.addons.decimal_precision as dp
from collections import OrderedDict

_logger = logging.getLogger(__name__)

class PosOrderLine(models.Model):
    _inherit = "pos.order.line"

    dict_value= fields.Char()


class PosOrder(models.Model):
    _inherit = "pos.order"


    def create_picking(self):
        """Create a picking for each order and validate it."""
        Picking = self.env['stock.picking']
        Move = self.env['stock.move']
        StockWarehouse = self.env['stock.warehouse']
        for order in self:
            print "order %s" % order.picking_type_id.id
            address = order.partner_id.address_get(['delivery']) or {}
            picking_type = order.picking_type_id
            print "picking_type %s" % picking_type
            return_pick_type = order.picking_type_id.return_picking_type_id or order.picking_type_id
            order_picking = Picking
            return_picking = Picking
            moves = Move
            location_id = order.location_id.id
            print "====================================%s" % order.location_id.name
            if order.partner_id:
                destination_id = order.partner_id.property_stock_customer.id
            else:
                if (not picking_type) or (not picking_type.default_location_dest_id):
                    customerloc, supplierloc = StockWarehouse._get_partner_locations()
                    destination_id = customerloc.id
                else:
                    destination_id = picking_type.default_location_dest_id.id
            if picking_type:
                print "picking_type"
                message = _(
                    "This transfer has been created from the point of sale session: <a href=# data-oe-model=pos.order data-oe-id=%d>%s</a>") % (
                          order.id, order.name)

                picking_vals = {
                    'origin': order.name,
                    'partner_id': address.get('delivery', False),
                    'date_done': order.date_order,
                    'picking_type_id': picking_type.id,
                    'company_id': order.company_id.id,
                    'move_type': 'direct',
                    'note': order.note or "",
                    'location_id': location_id,
                    'location_dest_id': destination_id,
                }
                print(picking_vals)
                pos_qty = any([x.qty >= 0 for x in order.lines])
                print "pos_qty %s" % pos_qty
                if pos_qty:
                    print "entered into pos_qty"
                    order_picking = Picking.create(picking_vals)
                    order_picking.message_post(body=message)
                neg_qty = any([x.qty < 0 for x in order.lines])
                if neg_qty:
                    return_vals = picking_vals.copy()
                    return_vals.update({
                        'location_id': destination_id,
                        'location_dest_id': return_pick_type != picking_type and return_pick_type.default_location_dest_id.id or location_id,
                        'picking_type_id': return_pick_type.id
                    })
                    return_picking = Picking.create(return_vals)
                    return_picking.message_post(body=message)

            for line in order.lines.filtered(lambda l: l.product_id.type in ['product', 'consu']):
                    print "--------------- dic_value-------------%s" %line.dict_value

                    if line.x_location:
                        if line.dict_value:
                            locations = ast.literal_eval(line.dict_value)
                            line_qty = line.qty

                            loc_id = self.env['stock.location'].search([('name', '=', line.x_location)])
                            print "loc id == %s" % loc_id
                            moves |= Move.create({
                                'name': line.name,
                                'product_uom': line.product_id.uom_id.id,
                                'picking_id': order_picking.id if line.qty >= 0 else return_picking.id,
                                'picking_type_id': picking_type.id if line.qty >= 0 else return_pick_type.id,
                                'product_id': line.product_id.id,
                                'product_uom_qty': abs(float(locations[line.x_location])),
                                'state': 'draft',
                                'location_id': loc_id.id,
                                'location_dest_id': destination_id if line.qty >= 0 else return_pick_type != picking_type and return_pick_type.default_location_dest_id.id or location_id,
                            })
                            line_qty -= float(locations[line.x_location])

                            if line_qty > 0:
                                for loc, qty in locations.iteritems():
                                    print "==============LINE QTY================%s"%line_qty
                                    print "==============QTY=====================%s"%qty

                                    if loc != line.x_location and float(qty)>0 and line_qty > 0:
                                        if float(qty) >= line_qty:
                                            # line_qty = float(qty) - line_qty
                                            print "qty diff =%s"%line_qty
                                            loc_id = self.env['stock.location'].search([('name', '=', loc)])
                                            moves |= Move.create({
                                                'name': line.name,
                                                'product_uom': line.product_id.uom_id.id,
                                                'picking_id': order_picking.id if line.qty >= 0 else return_picking.id,
                                                'picking_type_id': picking_type.id if line.qty >= 0 else return_pick_type.id,
                                                'product_id': line.product_id.id,
                                                'product_uom_qty': line_qty,
                                                'state': 'draft',
                                                'location_id': loc_id.id,
                                                'location_dest_id': destination_id if line.qty >= 0 else return_pick_type != picking_type and return_pick_type.default_location_dest_id.id or location_id,
                                            })

                                            print "executed move create"
                                            break
                                        else:
                                            print "ENETERD ELSE"
                                            line_qty = abs(float(qty)-line_qty)
                                            loc_id = self.env['stock.location'].search([('name', '=', loc)])
                                            moves |= Move.create({
                                                'name': line.name,
                                                'product_uom': line.product_id.uom_id.id,
                                                'picking_id': order_picking.id if line.qty >= 0 else return_picking.id,
                                                'picking_type_id': picking_type.id if line.qty >= 0 else return_pick_type.id,
                                                'product_id': line.product_id.id,
                                                'product_uom_qty': float(qty),
                                                'state': 'draft',
                                                'location_id': loc_id.id,
                                                'location_dest_id': destination_id if line.qty >= 0 else return_pick_type != picking_type and return_pick_type.default_location_dest_id.id or location_id,
                                            })
                        else:
                                loc_id = self.env['stock.location'].search([('name', '=', line.x_location)])
                                print "loc id == %s" % loc_id
                                moves |= Move.create({
                                    'name': line.name,
                                    'product_uom': line.product_id.uom_id.id,
                                    'picking_id': order_picking.id if line.qty >= 0 else return_picking.id,
                                    'picking_type_id': picking_type.id if line.qty >= 0 else return_pick_type.id,
                                    'product_id': line.product_id.id,
                                    'product_uom_qty': abs(line.qty),
                                    'state': 'draft',
                                    'location_id': loc_id.id,
                                    'location_dest_id': destination_id if line.qty >= 0 else return_pick_type != picking_type and return_pick_type.default_location_dest_id.id or location_id,
                                })

                    else:
                        moves |= Move.create({
                            'name': line.name,
                            'product_uom': line.product_id.uom_id.id,
                            'picking_id': order_picking.id if line.qty >= 0 else return_picking.id,
                            'picking_type_id': picking_type.id if line.qty >= 0 else return_pick_type.id,
                            'product_id': line.product_id.id,
                            'product_uom_qty': abs(line.qty),
                            'state': 'draft',
                            'location_id': location_id if line.qty >= 0 else destination_id,
                            'location_dest_id': destination_id if line.qty >= 0 else return_pick_type != picking_type and return_pick_type.default_location_dest_id.id or location_id,
                        })





            print "=========================== order picking is =%s" % order_picking.id
            # prefer associating the regular order picking, not the return
            order.write({'picking_id': order_picking.id or return_picking.id})

            if return_picking:
                order._force_picking_done(return_picking)
            if order_picking:
                print("1")
                order_picking.action_confirm()
                print("2")
                order_picking.force_assign()
                # order_picking.do_new_transfer()
                print("before")
                order.set_pack_operation_lot()
                print("after")
                order_picking.action_done()

            # when the pos.config has no picking_type_id set only the moves will be created
            if moves and not return_picking and not order_picking:
                moves.action_confirm()
                moves.force_assign()
                moves.filtered(lambda m: m.product_id.tracking == 'none').action_done()

        return True


class StockPick(models.Model):
    _inherit = 'stock.picking'

    def _prepare_pack_ops(self, quants, forced_qties):
        """ Prepare pack_operations, returns a list of dict to give at create """
        # TDE CLEANME: oh dear ...
        valid_quants = quants.filtered(lambda quant: quant.qty > 0)
        _Mapping = namedtuple('Mapping', ('product', 'package', 'owner', 'location', 'location_dst_id'))

        all_products = valid_quants.mapped('product_id') | self.env['product.product'].browse(
            p.id for p in forced_qties.keys()) | self.move_lines.mapped('product_id')
        computed_putaway_locations = dict(
            (product, self.location_dest_id.get_putaway_strategy(product) or self.location_dest_id.id) for product in
            all_products)

        product_to_uom = dict((product.id, product.uom_id) for product in all_products)
        picking_moves = self.move_lines.filtered(lambda move: move.state not in ('done', 'cancel'))
        for move in picking_moves:
            # If we encounter an UoM that is smaller than the default UoM or the one already chosen, use the new one instead.
            if move.product_uom != product_to_uom[move.product_id.id] and move.product_uom.factor > product_to_uom[
                move.product_id.id].factor:
                product_to_uom[move.product_id.id] = move.product_uom
        # if len(picking_moves.mapped('location_id')) > 1:
        #     raise UserError(_('The source location must be the same for all the moves of the picking.'))
        # if len(picking_moves.mapped('location_dest_id')) > 1:
        #     raise UserError(_('The destination location must be the same for all the moves of the picking.'))

        pack_operation_values = []
        # find the packages we can move as a whole, create pack operations and mark related quants as done
        top_lvl_packages = valid_quants._get_top_level_packages(computed_putaway_locations)
        for pack in top_lvl_packages:
            pack_quants = pack.get_content()
            pack_operation_values.append({
                'picking_id': self.id,
                'package_id': pack.id,
                'product_qty': 1.0,
                'location_id': pack.location_id.id,
                'location_dest_id': computed_putaway_locations[pack_quants[0].product_id],
                'owner_id': pack.owner_id.id,
            })
            valid_quants -= pack_quants

        # Go through all remaining reserved quants and group by product, package, owner, source location and dest location
        # Lots will go into pack operation lot object
        qtys_grouped = {}
        lots_grouped = {}
        for quant in valid_quants:
            key = _Mapping(quant.product_id, quant.package_id, quant.owner_id, quant.location_id,
                           computed_putaway_locations[quant.product_id])
            qtys_grouped.setdefault(key, 0.0)
            qtys_grouped[key] += quant.qty
            if quant.product_id.tracking != 'none' and quant.lot_id:
                lots_grouped.setdefault(key, dict()).setdefault(quant.lot_id.id, 0.0)
                lots_grouped[key][quant.lot_id.id] += quant.qty
        # Do the same for the forced quantities (in cases of force_assign or incomming shipment for example)
        for product, qty in forced_qties.items():
            if qty <= 0.0:
                continue
            key = _Mapping(product, self.env['stock.quant.package'], self.owner_id, self.location_id,
                           computed_putaway_locations[product])
            qtys_grouped.setdefault(key, 0.0)
            qtys_grouped[key] += qty

        # Create the necessary operations for the grouped quants and remaining qtys
        Uom = self.env['product.uom']
        product_id_to_vals = {}  # use it to create operations using the same order as the picking stock moves
        for mapping, qty in qtys_grouped.items():
            uom = product_to_uom[mapping.product.id]
            val_dict = {
                'picking_id': self.id,
                'product_qty': mapping.product.uom_id._compute_quantity(qty, uom),
                'product_id': mapping.product.id,
                'package_id': mapping.package.id,
                'owner_id': mapping.owner.id,
                'location_id': mapping.location.id,
                'location_dest_id': mapping.location_dst_id,
                'product_uom_id': uom.id,
                'pack_lot_ids': [
                    (0, 0, {'lot_id': lot, 'qty': 0.0, 'qty_todo': lots_grouped[mapping][lot]})
                    for lot in lots_grouped.get(mapping, {}).keys()],
            }
            product_id_to_vals.setdefault(mapping.product.id, list()).append(val_dict)

        for move in self.move_lines.filtered(lambda move: move.state not in ('done', 'cancel')):
            print(move.product_uom_qty)
            values = product_id_to_vals.pop(move.product_id.id, [])
            values[0]['location_id'] = move.location_id.id
            pack_operation_values += values
            print("pac ops vals %s"%pack_operation_values)
        return pack_operation_values



    @api.multi
    def do_prepare_partial(self):
        # TDE CLEANME: oh dear ...
        PackOperation = self.env['stock.pack.operation']

        # get list of existing operations and delete them
        existing_packages = PackOperation.search([('picking_id', 'in', self.ids)])  # TDE FIXME: o2m / m2o ?
        if existing_packages:
            existing_packages.unlink()
        for picking in self:
            forced_qties = {}  # Quantity remaining after calculating reserved quants
            picking_quants = self.env['stock.quant']
            # Calculate packages, reserved quants, qtys of this picking's moves
            for move in picking.move_lines:
                value = {}
                if move.state not in ('assigned', 'confirmed', 'waiting'):
                    continue
                move_quants = move.reserved_quant_ids
                picking_quants += move_quants
                forced_qty = (move.state == 'assigned') and move.product_qty - sum([x.qty for x in move_quants]) or 0
                # if we used force_assign() on the move, or if the move is incoming, forced_qty > 0
                if float_compare(forced_qty, 0, precision_rounding=move.product_id.uom_id.rounding) > 0:
                    if forced_qties.get(move.product_id):
                        value['fresh_record'] = False
                        value['location_dest_id']=move.location_dest_id.id
                        value['product_id'] = move.product_id.id
                        value['product_qty'] = forced_qty
                        value['product_uom_id'] = move.product_uom.id
                        value['location_id'] = move.location_id.id
                        value['picking_id'] = move.picking_id.id
                        PackOperation.create(value)
                        # print("inside11")
                        # forced_qties[move.product_id] += forced_qty
                    else:
                        # forced_qties[move.product_id] = forced_qty
                        value['fresh_record'] = False
                        value['location_dest_id']=move.location_dest_id.id
                        value['product_id'] = move.product_id.id
                        value['product_qty'] = forced_qty
                        value['product_uom_id'] = move.product_uom.id
                        value['location_id'] = move.location_id.id
                        value['picking_id'] = move.picking_id.id
                        PackOperation.create(value)
            # for vals in picking._prepare_pack_ops(picking_quants, forced_qties):
            #     vals['fresh_record'] = False
            #     PackOperation.create(vals)
        # recompute the remaining quantities all at once
        self.do_recompute_remaining_quantities()
        self.write({'recompute_pack_op': False})


0
Avatar
Descartar
Avatar
Simone
Mejor respuesta

I have the usual problem do you have any help? 

Sorry my English!

0
Avatar
Descartar
¿Le interesa esta conversación? ¡Participe en ella!

Cree una cuenta para poder utilizar funciones exclusivas e interactuar con la comunidad.

Inscribirse
Publicaciones relacionadas Respuestas Vistas Actividad
Point of Sale: No Picking ID when creating order
pos inventory picking
Avatar
Avatar
Avatar
2
feb 18
4701
POS poor performance while inventory is (in real time)
pos inventory
Avatar
Avatar
1
jul 22
4302
Product with no sale or zero sale in pos
pos inventory
Avatar
0
may 20
3187
PoS Orders in Sales Details Resuelto
pos inventory
Avatar
Avatar
2
jul 19
7568
Odoo 12 : Point of sale : buying an item in sets and selling it in sets or in parts
pos inventory
Avatar
0
nov 18
3343
Comunidad
  • Tutoriales
  • Documentación
  • Foro
Código abierto
  • Descargar
  • GitHub
  • Runbot
  • Traducciones
Servicios
  • Alojamiento Odoo.sh
  • Ayuda
  • Actualizar
  • Desarrollos personalizados
  • Educación
  • Encontrar un asesor fiscal
  • Encontrar un partner
  • Convertirse en partner
Sobre nosotros
  • Nuestra empresa
  • Activos de marca
  • Contacta con nosotros
  • Puestos de trabajo
  • Eventos
  • Podcast
  • Blog
  • Clientes
  • Información legal • Privacidad
  • Seguridad
الْعَرَبيّة Català 简体中文 繁體中文 (台灣) Čeština Dansk Nederlands English Suomi Français Deutsch हिंदी Bahasa Indonesia Italiano 日本語 한국어 (KR) Lietuvių kalba Język polski Português (BR) română русский язык Slovenský jazyk slovenščina Español (América Latina) Español ภาษาไทย Türkçe українська Tiếng Việt

Odoo es un conjunto de aplicaciones de código abierto que cubren todas las necesidades de tu empresa: CRM, comercio electrónico, contabilidad, inventario, punto de venta, gestión de proyectos, etc.

La propuesta única de valor de Odoo es ser muy fácil de usar y totalmente integrado.

Website made with

Odoo Experience on YouTube

1. Use the live chat to ask your questions.
2. The operator answers within a few minutes.

Live support on Youtube
Watch now