Skip to Content
Odoo Menú
  • Registra entrada
  • Prova-ho gratis
  • Aplicacions
    Finances
    • Comptabilitat
    • Facturació
    • Despeses
    • Full de càlcul (IA)
    • Documents
    • Signatura
    Vendes
    • CRM
    • Vendes
    • Punt de venda per a botigues
    • Punt de venda per a restaurants
    • Subscripcions
    • Lloguer
    Imatges de llocs web
    • Creació de llocs web
    • Comerç electrònic
    • Blog
    • Fòrum
    • Xat en directe
    • Aprenentatge en línia
    Cadena de subministrament
    • Inventari
    • Fabricació
    • PLM
    • Compres
    • Manteniment
    • Qualitat
    Recursos humans
    • Empleats
    • Reclutament
    • Absències
    • Avaluacions
    • Recomanacions
    • Flota
    Màrqueting
    • Màrqueting Social
    • Màrqueting per correu electrònic
    • Màrqueting per SMS
    • Esdeveniments
    • Automatització del màrqueting
    • Enquestes
    Serveis
    • Projectes
    • Fulls d'hores
    • Servei de camp
    • Suport
    • Planificació
    • Cites
    Productivitat
    • Converses
    • Validacions
    • IoT
    • VoIP
    • Coneixements
    • WhatsApp
    Aplicacions de tercers Odoo Studio Plataforma d'Odoo al núvol
  • Sectors
    Comerç al detall
    • Llibreria
    • Botiga de roba
    • Botiga de mobles
    • Botiga d'ultramarins
    • Ferreteria
    • Botiga de joguines
    Food & Hospitality
    • Bar i pub
    • Restaurant
    • Menjar ràpid
    • Guest House
    • Distribuïdor de begudes
    • Hotel
    Immobiliari
    • Agència immobiliària
    • Estudi d'arquitectura
    • Construcció
    • Gestió immobiliària
    • Jardineria
    • Associació de propietaris de béns immobles
    Consultoria
    • Empresa comptable
    • Partner d'Odoo
    • Agència de màrqueting
    • Bufet d'advocats
    • Captació de talent
    • Auditoria i certificació
    Fabricació
    • Textile
    • Metal
    • Mobles
    • Menjar
    • Brewery
    • Regals corporatius
    Salut i fitness
    • Club d'esport
    • Òptica
    • Centre de fitness
    • Especialistes en benestar
    • Farmàcia
    • Perruqueria
    Trades
    • Servei de manteniment
    • Hardware i suport informàtic
    • Sistemes d'energia solar
    • Shoe Maker
    • Serveis de neteja
    • Instal·lacions HVAC
    Altres
    • Nonprofit Organization
    • Agència del medi ambient
    • Lloguer de panells publicitaris
    • Fotografia
    • Lloguer de bicicletes
    • Distribuïdors de programari
    Browse all Industries
  • Comunitat
    Aprèn
    • Tutorials
    • Documentació
    • Certificacions
    • Formació
    • Blog
    • Pòdcast
    Potenciar l'educació
    • Programa educatiu
    • Scale-Up! El joc empresarial
    • Visita Odoo
    Obtindre el programari
    • Descarregar
    • Comparar edicions
    • Novetats de les versions
    Col·laborar
    • GitHub
    • Fòrum
    • Esdeveniments
    • Traduccions
    • Converteix-te en partner
    • Services for Partners
    • Registra la teva empresa comptable
    Obtindre els serveis
    • Troba un partner
    • Troba un comptable
    • Contacta amb un expert
    • Serveis d'implementació
    • Referències del client
    • Suport
    • Actualitzacions
    Github Youtube Twitter Linkedin Instagram Facebook Spotify
    +1 (650) 691-3277
    Programar una demo
  • Preus
  • Ajuda

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

  • CRM
  • e-Commerce
  • Comptabilitat
  • Inventari
  • PoS
  • Projectes
  • MRP
All apps
You need to be registered to interact with the community.
All Posts People Badges
Etiquetes (View all)
odoo accounting v14 pos v15
About this forum
You need to be registered to interact with the community.
All Posts People Badges
Etiquetes (View all)
odoo accounting v14 pos v15
About this forum
Ajuda

PoS Sale from 2 locations

Subscriure's

Get notified when there's activity on this post

This question has been flagged
posinventorypicking
3 Respostes
6292 Vistes
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
Best Answer

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
Best Answer

I have the usual problem do you have any help? 

Sorry my English!

0
Avatar
Descartar
Enjoying the discussion? Don't just read, join in!

Create an account today to enjoy exclusive features and engage with our awesome community!

Registrar-se
Related Posts Respostes Vistes Activitat
Point of Sale: No Picking ID when creating order
pos inventory picking
Avatar
Avatar
Avatar
2
de febr. 18
4716
POS poor performance while inventory is (in real time)
pos inventory
Avatar
Avatar
1
de jul. 22
4333
Product with no sale or zero sale in pos
pos inventory
Avatar
0
de maig 20
3200
PoS Orders in Sales Details Solved
pos inventory
Avatar
Avatar
2
de jul. 19
7603
Odoo 12 : Point of sale : buying an item in sets and selling it in sets or in parts
pos inventory
Avatar
0
de nov. 18
3362
Community
  • Tutorials
  • Documentació
  • Fòrum
Codi obert
  • Descarregar
  • GitHub
  • Runbot
  • Traduccions
Serveis
  • Allotjament a Odoo.sh
  • Suport
  • Actualització
  • Desenvolupaments personalitzats
  • Educació
  • Troba un comptable
  • Troba un partner
  • Converteix-te en partner
Sobre nosaltres
  • La nostra empresa
  • Actius de marca
  • Contacta amb nosaltres
  • Llocs de treball
  • Esdeveniments
  • Pòdcast
  • Blog
  • Clients
  • Informació legal • Privacitat
  • Seguretat
الْعَرَبيّة 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 és un conjunt d'aplicacions empresarials de codi obert que cobreix totes les necessitats de la teva empresa: CRM, comerç electrònic, comptabilitat, inventari, punt de venda, gestió de projectes, etc.

La proposta única de valor d'Odoo és ser molt fàcil d'utilitzar i estar totalment integrat, ambdues alhora.

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