def test_parse_quote_with_quantities():
    """
    Parse a quote definition including quantities.
    """
    quote = parse_quote(TESLA_QUANTITIES_QUOTE)
    checkQuote(quote)
    assert quote["title"] == "Configurateur de Tesla Model 3"
    assert quote["sect"]["logo"]["path"] == "tests/samples/tesla_logo.png"
    assert quote["sect"]["logo"]["file"] == "tests/samples/tesla_logo.png"
    assert quote["has_quantities"] is True
    assert quote["price"]["total_vat_excl"] == 35000
    assert len(quote["prestations"]) == 2
    assert len(quote["all_prestations"]) == 2
    assert len(quote["optional_prestations"]) == 0
    assert quote["prestations"][0][
        "title"] == "Création des configurations sur le CPQ"
    assert quote["prestations"][0]["price"] == 5000
    assert quote["prestations"][0]["total"] == 5000
    assert quote["prestations"][0]["optional"] is False
    assert quote["prestations"][0]["quantity"] == 1
    assert quote["prestations"][1]["title"] == "Intégration de l'UI"
    assert quote["prestations"][1]["price"] == 10000
    assert quote["prestations"][1]["total"] == 30000
    assert quote["prestations"][1]["optional"] is False
    assert quote["prestations"][1]["quantity"] == 3
def test_parse_nested_section_quote_with_optional():
    """
    Parse a quote definition with nested (in section) optional prestations.
    """
    quote = parse_quote(COMMERCE_NESTED_OPTIONAL_QUOTE)
    checkQuote(quote)
    assert quote["title"] == "Configurateur de Tesla Model 3"
    assert quote["price"]["total_vat_excl"] == 23940
    assert len(quote["prestations"]) == 2
    assert quote["optional_price"]["total_vat_excl"] == 400
    assert len(quote["all_prestations"]) == 5
    assert len(quote["optional_prestations"]) == 2
    assert quote["has_quantities"] is True
    assert quote["all_prestations"][2][
        "title"] == "Fonction spécial optionnelle n°1"
    assert quote["all_prestations"][2]["total"] == 320
    assert quote["all_prestations"][2]["optional"] is True
    assert (quote["optional_prestations"][0]["title"] ==
            "Fonction spécial optionnelle n°1")
    assert quote["optional_prestations"][0]["price"] == 80
    assert quote["optional_prestations"][0]["optional"] is True
    assert quote["sections"][0]["price"]["total_vat_excl"] == 19540
    assert quote["sections"][0]["optional_price"]["total_vat_excl"] == 19940
    assert quote["sections"][0]["optional"] == False
    assert quote["sections"][1]["price"]["total_vat_excl"] == 4400
    assert quote["sections"][1]["optional_price"]["total_vat_excl"] == 4400
    assert quote["sections"][1]["optional"] == False
def test_parse_quote_with_batches():
    """
    Parse a quote definition with prestation batches (and sections).
    """
    quote = parse_quote(TESLA_BATCHES_QUOTE)
    checkQuote(quote)
    assert quote["sect"]["logo"] is None
    assert len(quote["all_prestations"]) == 5
    assert len(quote["prestations"]) == 3
    assert len(quote["sections"]) == 2
    assert len(quote["batches"]) == 3
    assert quote["price"]["total_vat_excl"] == 46300
    assert (quote["all_prestations"][0]["title"] ==
            "Création des configurations sur le CPQ")
    assert quote["all_prestations"][0]["price"] == 5000
    assert quote["batches"][0]["name"] == "1"
    assert quote["batches"][0]["price"] == 17000
    assert quote["batches"][1]["name"] == "2"
    assert quote["batches"][1]["price"] == 4300
    assert quote["batches"][2]["name"] == "3"
    assert quote["batches"][2]["price"] == 25000
    assert quote["all_prestations"][0]["batch"] == "1"
    assert quote["all_prestations"][1]["batch"] == "1"
    assert quote["all_prestations"][2]["batch"] == "1"
    assert quote["all_prestations"][3]["batch"] == "2"
    assert quote["all_prestations"][4]["batch"] == "3"
    assert quote["prestations"][0]["prestations"][0]["batch"] == "1"
    assert quote["prestations"][0]["prestations"][1]["batch"] == "1"
    assert quote["prestations"][1]["prestations"][0]["batch"] == "1"
    assert quote["prestations"][1]["prestations"][1]["batch"] == "2"
    assert quote["prestations"][2]["batch"] == "3"
def test_parse_quote_with_optional_sections():
    """
    Parse a quote definition with prestation optional sections.
    """
    definition = copy.deepcopy(TESLA_SECTIONS_QUOTE)
    definition["prestations"][1]["optional"] = True
    quote = parse_quote(definition)
    # import pprint
    # pprint.pprint(quote)
    checkQuote(quote)
    assert quote["title"] == "Configurateur de Tesla Model 3"
    # Must always return a prestation list, flattened.
    assert len(quote["all_prestations"]) == 5
    # The not flattened representation.
    assert len(quote["prestations"]) == 3
    assert len(quote["sections"]) == 2
    pprint.pprint(quote["optional_prestations"])
    assert len(quote["optional_prestations"]) == 2
    assert len(quote["optional_sections"]) == 1
    assert quote["price"]["total_vat_excl"] == 40000
    assert quote["optional_price"]["total_vat_excl"] == 6300
    assert quote["all_prestations"][2]["title"] == "Intégration Javascript"
    assert quote["all_prestations"][2]["price"] == 2000
    assert quote["all_prestations"][2]["optional"] == True
    assert quote["all_prestations"][3]["title"] == "Intégration CSS"
    assert quote["all_prestations"][3]["price"] == 4300
    assert quote["all_prestations"][3]["optional"] == True
    assert (quote["sections"][1]["title"] ==
            "Intégration e-commerce du CPQ sur tesla.com")
    assert quote["sections"][1]["price"]["total_vat_excl"] == None
    assert quote["sections"][1]["optional_price"]["total_vat_excl"] == 6300
    assert quote["sections"][1]["optional"] == True
def test_parse_quote_with_sections():
    """
    Parse a quote definition with prestation sections (recursive prestations).
    """
    quote = parse_quote(TESLA_SECTIONS_QUOTE)
    checkQuote(quote)
    assert quote["title"] == "Configurateur de Tesla Model 3"
    assert quote["sect"]["logo"] is None
    # Must always return a prestation list, flattened.
    assert len(quote["all_prestations"]) == 5
    # The not flattened representation.
    assert len(quote["prestations"]) == 3
    assert len(quote["sections"]) == 2
    assert len(quote["optional_prestations"]) == 0
    assert quote["price"]["total_vat_excl"] == 46300
    assert quote["optional_price"]["total_vat_excl"] == None
    assert (quote["all_prestations"][0]["title"] ==
            "Création des configurations sur le CPQ")
    assert quote["all_prestations"][0]["price"] == 5000
    assert (quote["all_prestations"][0]["section"] ==
            "Développement du Nouveau CPQ Tesla")
    assert quote["sections"][0][
        "title"] == "Développement du Nouveau CPQ Tesla"
    assert quote["sections"][0]["price"]["total_vat_excl"] == 15000
    assert quote["sections"][0]["optional_price"]["total_vat_excl"] == 15000
    assert (quote["sections"][1]["title"] ==
            "Intégration e-commerce du CPQ sur tesla.com")
    assert quote["sections"][1]["price"]["total_vat_excl"] == 6300
    assert quote["sections"][1]["optional_price"]["total_vat_excl"] == 6300
def test_parse_simple_quote():
    """
    Parse a simple quote definition.
    """
    quote = parse_quote(TESLA_16_01_QUOTE)
    checkQuote(quote)
    assert quote["title"] == "Configurateur de Tesla Model 3"
    assert quote["sect"]["logo"]["path"] == "tests/samples/tesla_logo.png"
    assert quote["sect"]["logo"]["file"] == "tests/samples/tesla_logo.png"
    assert quote["price"]["total_vat_excl"] == 40000
    assert len(quote["prestations"]) == 4
    assert quote["optional_price"]["total_vat_excl"] == 14000
    assert len(quote["all_prestations"]) == 4
    assert len(quote["optional_prestations"]) == 1
    assert quote["has_quantities"] is False
    assert quote["prestations"][0][
        "title"] == "Création des configurations sur le CPQ"
    assert quote["prestations"][0]["price"] == 5000
    assert quote["prestations"][0]["optional"] is False
    assert quote["prestations"][2][
        "title"] == "Growth-hacking après mise en ligne"
    assert quote["prestations"][2]["price"] == 14000
    assert quote["prestations"][2]["optional"] is True
    assert (quote["optional_prestations"][0]["title"] ==
            "Growth-hacking après mise en ligne")
    assert quote["optional_prestations"][0]["price"] == 14000
    assert quote["optional_prestations"][0]["optional"] is True
def test_parse_quote_price_string():
    """
    A prestation price can be set to a string.
    """
    definition = copy.deepcopy(TESLA_16_01_QUOTE)
    definition["prestations"][0]["price"] = "(inclus)"
    quote = parse_quote(definition)
    checkQuote(quote)
    assert quote["price"]["total_vat_excl"] == 35000
    assert len(quote["prestations"]) == 4
    assert quote["prestations"][0]["price"] == "(inclus)"
def test_parse_quote_price_none():
    """
    A prestation price can be set to None (not specified).
    """
    definition = copy.deepcopy(TESLA_16_01_QUOTE)
    definition["prestations"][0]["price"] = None
    quote = parse_quote(definition)
    checkQuote(quote)
    assert quote["price"]["total_vat_excl"] == 35000
    assert len(quote["prestations"]) == 4
    assert quote["prestations"][0]["price"] == None
def test_parse_simple_quote_tva():
    """
    A prestation price can include VAT.
    """
    definition = copy.deepcopy(TESLA_16_01_QUOTE)
    definition["vat_rate"] = 20
    quote = parse_quote(definition)
    checkQuote(quote)
    assert len(quote["prestations"]) == 4
    assert quote["vat_rate"] == 20
    assert quote["price"]["total_vat_excl"] == 40000
    assert quote["price"]["vat"] == 8000
    assert quote["price"]["total_vat_incl"] == 48000
def test_parse_simple_quote_no_optional_tva():
    """
    Parse a simple quote definition which include VAT but no optional.
    """
    definition = copy.deepcopy(TESLA_SECTIONS_QUOTE)
    definition["vat_rate"] = 20
    quote = parse_quote(definition)
    checkQuote(quote)
    assert quote["vat_rate"] == 20
    assert quote["title"] == "Configurateur de Tesla Model 3"
    assert len(quote["all_prestations"]) == 5
    assert len(quote["prestations"]) == 3
    assert len(quote["sections"]) == 2
    assert len(quote["optional_prestations"]) == 0
    assert quote["price"]["total_vat_excl"] == 46300
    assert quote["optional_price"]["total_vat_excl"] == None
def test_parse_quote_price_all_none_or_string():
    """
    All prestation prices can be set to None or String. Then the total must be None.
    """
    definition = copy.deepcopy(TESLA_16_01_QUOTE)
    definition["prestations"][0]["price"] = None
    definition["prestations"][1]["price"] = "à définir"
    definition["prestations"][3]["price"] = "à définir"
    quote = parse_quote(definition)
    checkQuote(quote)
    assert quote["price"]["total_vat_excl"] == None
    assert quote["optional_price"]["total_vat_excl"] == 14000
    assert len(quote["prestations"]) == 4
    assert quote["prestations"][0]["price"] == None
    assert quote["prestations"][1]["price"] == "à définir"
    assert quote["prestations"][2]["price"] == 14000
    assert quote["prestations"][2]["optional"] is True