simple and extendable shop
Don't do using namespace std;

Qualify names properly with std:: where necessary.



string getProdName() const { return prodName; }
int    getQuant() const { return quant; }


Avoid abbreviations as they harm code clarity. Most IDE's provide auto-completion, so abbreviations don't save typing anyway.



receipt(const string&amp; prdNm, int qnt)
      : prodName(prdNm), quant(qnt)
{}


The initializer list allows you to use the same name for the function argument as for the member variable, so this would be fine:

receipt(std::string productName, int quantity)
      : productName(std::move(productName)), quantity(quantity)
{}


(Since the product name is a "sink argument" (we want to copy and store it locally), we can take it by value and move it into place).



I don't think it's a good idea to overload operator&lt; for these classes. These aren't mathematical types, so there's no inherent ordered relationship. It would make just as much sense to sort by product price as by name.

We're using the operator&lt; for sorting in a particular structure, so we want to associate the ordering with that structure, not with the type itself. We can do that using a "functor" class to define comparison, and specifying it as a template argument:

struct ProductLessThanByName
{
    bool operator()(const Product&amp; a, const Product&amp; b) const {
        return a.getName() &lt; b.getName();
    }
};

...

    std::map&lt;Product, int, ProductLessThanByName&gt; products;




record is a rather ambiguous name. Maybe client_purchases or purchase_record or something might be better.

Since we already have the receipt class, that stores product and quantity, we could perhaps use that internally.



Although encapsulation is important, people often interpret it as "make all member variables private and add getter / setter functions". This is fine for classes that have associated logic in member functions, or where we can't change a member without extra work (we must adhere to the class invariants).

However, it's unnecessary for simple data containers. If we don't want to allow the user to change a member of the product or receipt classes, we can enforce that by giving them a const&amp; to the class. So we can save a lot of work and use plain structs. e.g.:

struct  receipt
{
    std::string productName;
    int quantity;
};




It's probably better to use unsigned types for the quantity and price. We don't expect these to ever be negative, and it's easier to rule out invalid values.



As far as the design goes, I'm not sure we need to add clients outside of a transaction. I don't think it really makes sense to "remove" a client either. We have to keep the transaction history intact.

I think it would be helpful to separate the idea of "adding a product-type to the database" from "adding stock (actual items of a product-type) to the shop".

As Kyy13 notes in the comments, we need to store the price at which we sold an item in the transaction history.