Création d'un panier d'achat (pour click-and-collect)

Bonjour tout le monde

Je suis en train de créer une application pour un restaurant qui a besoin d’une solution afin de continuer son activité en ces temps de pandémie.

C’est pour cela que je voudrais savoir si vous connaissez une solution pour pouvoir créer un panier d’achat afin d’implémenter (plus tard) le click-and-collect.

Voilà ou j’en suis…


J’ai crée cette TableView et voilà le TableViewController associé

Voilà mes 2 models :

1)ProductLine.swift

import UIKit

class ProductLine {

var name : String
var products : [Product]
init(named : String,includeProducts : [Product]) {
    name = named
    products = includeProducts
}
class func getProductLines()-> [ProductLine]
{
    return [entrées(),plats(),salades(),planches(),menuEnfant(),burgers(),fish(),desserts()]
}




private class func entrées() -> ProductLine {
    //  (0) Entrees : Oeuf cocotte, Potage , Terrine , Cassolette , Camenbert
    var products = [Product]()
    
    products.append(Product(imageName: "oeufCocotte", title: "Tartare de saumon", description: "Une delicieuse entrée avec de l'avocat et de la mangue",price : "7.40€" ))
    products.append(Product(imageName: "potage", title: "Croustillant de chèvre", description: "Un delicieux potage",price : "4.70€"))
    products.append(Product(imageName: "terrine", title: "Terrine de campagne maison", description: "Une delicieuse terrine",price : "5.50€"))
    products.append(Product(imageName: "camembert", title: "Demi camembert rôti au miel et jambon serrano", description: "Un delicieux camenbert",price : "6.90€"))
    
    return ProductLine(named: "Entrées", includeProducts: products)
}

//  (1) Plats : Risotto de coquillette,Entrecote,Rosace,Tartare

private class func plats() -> ProductLine
{
    var products = [Product]()
    
    products.append(Product(imageName: "saumon", title: "Pavé de saumon", description: "Pavé de sumon et ses legumes Wok",price: "16.20€"))
    products.append(Product(imageName: "entrecote", title: "Entrecôte", description: "Entrecote 300g,sauce poivre,frites et salades",price: "19.90€"))
    
    products.append(Product(imageName: "tartare", title: "Tartare de boeuf", description: "Un delicieux tartare avec des pommes de terre sautées et de la salade",price: "15.00€"))
    
    
    return ProductLine(named: "Plats", includeProducts: products)
}

//  (2) Salades: Salade césar ,salade paysanne

private class func salades() -> ProductLine
{
    var products = [Product]()
    
    
    products.append(Product(imageName: "cesar", title: "Salade César", description: "Poulet,parmesan,lardons,oeuf,salade,tomates,oignons,croûtons,sauce césar",price: "13.90€"))
    products.append(Product(imageName: "paysanne", title: "Poké bowl au saumon", description: "Guacamole,mangue,riz,poivron rouge,concombre,choux,fèves,carotte,graines de sésame",price: "15.00€"))
    
    
    return ProductLine(named: "Salade & Poké bowl", includeProducts: products)
}

//  (3) Planches : Planches de fromage, planche de charcuterie , planche mixte
private class func planches() -> ProductLine
{
    var products = [Product]()
    
    products.append(Product(imageName: "plancheFromage", title: "Planche de fromages", description: "Differents fromages",price: "12.90€"))
    products.append(Product(imageName: "plancheCharcuterie", title: "Planche de charcuteries", description: "Differentes charcuteries",price: "12.90€"))
    products.append(Product(imageName: "plancheMixte", title: "Planche mixte", description: "Planche de charcuterie et fromage",price: "12.90€"))
    
    
    return ProductLine(named: "Planches", includeProducts: products)
}

//  (4)Menu enfants

private class func menuEnfant() -> ProductLine
{
    var products = [Product]()
    
    products.append(Product(imageName: "burgerEnfant", title: "Burger enfant", description: "Bœuf haché maison, cheddar,tomate,salade,oignon",price: "9€"))
    products.append(Product(imageName: "coquillettes", title: "Coquillette à la parisienne", description: "Delicieuses coquillettes",price: "9€"))
    
    return ProductLine(named: "Le coin des enfants de - 10 ans", includeProducts: products)
}


// (5) Burgers

private class func burgers() -> ProductLine
{
    var products = [Product]()
    
    products.append(Product(imageName: "Ococher", title: "Ô'Cocher", description: "Bœuf haché maison, camembert,brisures de truffes,magret séché,salade,fondue de tomates et oignons",price: "16.90€"))
    products.append(Product(imageName: "mexicain", title: "Le Mexicain", description: "Bœuf haché maison,cheddar épicé,chorizo poêlé, guacamole, œuf,salade,fondue de tomates et oignons",price: "16.00€"))
    products.append(Product(imageName: "milanais", title: "Le Milanais", description: "Blanc de poulet pané, cantal, salade, tomate,oignons, sauce pesto",price: "15.00€"))
    products.append(Product(imageName: "auvergnat", title: "L'Auvergnat", description: "Bœuf haché maison, cantal,bacon,salade,fondue de tomates oignons,sauce bleu d’Auvergne",price: "15.00€"))
    products.append(Product(imageName: "paname", title: "Le Paname", description: "Bœuf haché maison,cantal,bacon,champignons,salade, fondue de tomates,oignons et sauce champignons",price: "15.00€"))
    
    products.append(Product(imageName: "vegetarien", title: "Végétarien", description: "Galette de courgette et carottes champignon,cantal salade, oignons,fondue de tomates",price: "14.80€"))
    
    return ProductLine(named: "Burgers", includeProducts: products)
}
// (6) Fish
private class func fish() -> ProductLine
{
    var products = [Product]()
    products.append(Product(imageName: "fish", title: "Fish and chips", description: "",price: "14.00€"))
    
    return ProductLine(named: "Fish", includeProducts: products)
}

// (7) Dessert
private class func desserts() -> ProductLine
{
    var products = [Product]()
    
    products.append(Product(imageName: "mousseChocolat", title: "Mousse au chocolat", description: "Delicieuse mousse au chocolat",price: "5.00€"))
    products.append(Product(imageName: "cremeBrulee", title: "Crème brûlée", description: "Delicieuse crème brulée",price: "5.00€"))
    products.append(Product(imageName: "saladeFruits", title: "Salade de fruits", description: "Delicieuse salade de fruits",price: "5.00€"))
    products.append(Product(imageName: "cheese", title: "Cheese cake", description: "Delicieux délice",price: "6.00€"))
    products.append(Product(imageName: "bouleGlace", title: "Boule de glace artisan pedone", description: "Glace delicieuse",price: "3.00€"))
    
    
    
    return ProductLine(named: "Desserts", includeProducts: products)
}

}

  1. Product.swift

import UIKit

class Product {

var image : UIImage
var title : String
var description : String
var price : String

init(imageName : String,title : String,description : String,price : String) {
    
    self.title = title
    self.description = description
    self.price = price
    if let image = UIImage(named: imageName){
        self.image = image
    }else{
        self.image = UIImage(named: "default")!
    }
    
}

}

Est ce que quelqu’un aurait une idée, s’il vous plait?

Hello,

Sans avoir fait de tests, la comme ça, à chaud, tu pourrais utiliser un dictionnaire à entrer dans les UserDefaults afin de garder en mémoire l’ID du produit choisi et sa quantité.

A partir de là, tu es capable de calculer le prix du panier.

Salut.

Avant de répondre pourrais-tu nous en dire plus sur :

Où sont stocker les data produits ?
Comment gères-tu les comptes client ?

Bonjour Yann.Merci pour cette réponse rapide.

J’avais commencé à modifier ma class Product en y ajoutant une propriété idProduct :

Du coup,je pense que ça devient totalement inutile si je crée un dictionnaire entré dans UserDefaults?Qu’en penses-tu?..L’application est presque terminée mais je pédale dans la semoule.

Salut Alexandre.Merci d’avoir répondu.

Je voudrais utiliser Firebase pour cela.J’ai implémenté les authentifications Google,email et Apple avec Firebase .Elles fonctionnent toutes.J’essaie de trouver un moyen via Firebase d’y stocker les data produits et comptes clients mais je bloque depuis 2 semaines.


Pour ce qui est du profil utilisateur,pas encore crée la vue dédiée.Je pense utiliser une TableView.

Hello,

Voici, en gros ce que j’avais fait :

1/ J’ai un UIStepper pour gérer la quantité de chaque produit à ajouter. L’action est la suivante (la seulement l’affichage) :

@IBAction func changeQuantityValueAction() {
    uiQuantityLabel.text = String(Int(uiQuantityStepper.value))
}

2/ Au clic sur le UIButton « Ajouter au panier » (on ajoute au panier la quantité désirée et on se rend sur page Panier) :

@IBAction func addToCartAction() {
    _appManager.setCartBadge(number: String(Int(uiQuantityStepper.value)), zero: false)
    _cartViewController.addItemsToCart(id: _product!.id, quantity: Int(uiQuantityStepper.value), product: _product!)
    navigationController?.popViewController(animated: true)
    self.dismiss(animated: true, completion: nil)
}

3/ _appManager.setCartBadge pour gérer le badge sur la TabBar

func setCartBadge(number:String, zero:Bool) {
    let appDelegate         = UIApplication.shared.delegate as! AppDelegate
    let tabBarController    = appDelegate.window!.rootViewController as! UITabBarController
        
    var actualBadgeValue    = 0
    var newBadgeValue       = 0
        
    if let items = tabBarController.tabBar.items {
        for item in items {
            if item.tag == 42 {
                if let badgeValue = item.badgeValue {
                    actualBadgeValue = Int(badgeValue)!
                }
                    
                if zero {
                    newBadgeValue = Int(number)!
                } else {
                    newBadgeValue = actualBadgeValue + Int(number)!
                }
                    
                item.badgeValue = String(newBadgeValue)
            }
        }
    }
}

4/ Dans mon AppManager, j’ai aussi ça pour gérer et vider mon panier :

struct Cart {
    static var cart = [Int:[Int:[Product]]]()
}

func clearCart() {
    AppManager.Cart.cart = [Int:[Int:[Product]]]()
}

5/ Le addToCart du CartViewController :

func addItemsToCart(id:Int, quantity:Int, product:Product) {
    if let cartIndex = AppManager.Cart.cart.index(forKey: id) {
        let cartValue   = AppManager.Cart.cart[cartIndex].value
        if let productIndex = cartValue.first {
            let newQuantity = productIndex.key + quantity
            AppManager.Cart.cart.updateValue([newQuantity:[product]], forKey: id)
        }
    } else {
        AppManager.Cart.cart.updateValue([quantity:[product]], forKey: id)
    }
}

En fait, contrairement à ce que je t’ai dit, je ne stocke pas mon object Cart dans les UserDefaults, donc le panier ne se sauvegarde pas entre chaque session (car mes produits changeaient régulièrement et ça n’aurait pas eu de sens). Mais il est tout à fait possible de le faire à mon avis, surtout si, comme ça a l’air d’être le cas, les produits sont « en dur » dans l’application.

C’est un « vieux » code, je n’ai plus toutes les subtilités en tête mais je pense que ça te fait une bonne base de départ.

Les produits en dur dans l’appli !!! :scream:

Lorsque j’ai posé mes 2 questions précédemment s’était justement pour être certain que le produit n’était pas en dur dans l’application car c’est vraiment pas à faire.
Imagine un changement de libellé d’un produits : il faut refaire valider l’appli à Apple. Ou autre cas : comment sais-tu si le produit est en rupture ?

Perso pour assurer une compatibilité cross platform je gérerai le panier_client directement dans la base de données.
Il faudrait à mon sens d’abord créer le webservice avec les méthodes suivantes :

getPanierClient(idClient)
updateQtePanier(quantite, idArticle, idClient)
confirmPanier(idClient)
razPanier(idClient)

Se ne sont que quelques idées qui me viennent de suite en têtes.

Ça te permet ensuite de faire des requêtes depuis ton appli iOS / android / webapp (php par exemple)

Mais par pitié pas de produits en dur.
Après libre à toi de stocker temporairement le panier sur le iDevice si tu veux faire du « hors connexion »

Oui, j’ai hésiter à ajouter : « Ce qui est, à mon avis, une très mauvaise idée à moins que d’être sûr à 100% que les produits ne changeront pas. » :wink:

Effectivement,les produits ne sont pas destinés à changer.Mais ce ne sera pas déconnant de mettre la solution en pratique…Je vais implémenter tout ça ce week-end et je posterai le résultat ici.Ça aidera ceux qui se grattent la tête comme moi…

Les produits ne sont pas destinés à changer, peut-être, mais quid des changements de prix, des promotions spéciales pour un événement, des plats spéciaux à faible durée de vie (genre le repas spécial Saint-Valentin, ou la tarte au chocolat de Pâques, etc …) ?

Je cherchais justement une citation que tu aurais pu dire @Draken !

Comme par exemple : « Tout système dont la fiabilité dépend d’un être humain n’est pas fiable. »

Mais tu es rester très terre à terre pour une fois :wink:

En gros être sur à 100% que rien ne changera c’est juste impossible !

1 J'aime

Le changement est la seule chose constante dans l’univers !

3 J'aimes