To solve this optimization problem, we need to define the decision variables, the objective function, and the constraints.

Let's denote:
- $x$ as the number of bottles of perfume to buy and sell,
- $y$ as the number of bottles of mascara to buy and sell.

The objective is to maximize profit. The profit from selling one bottle of perfume is $20, and from selling one bottle of mascara is $15. Therefore, the total profit can be represented as $20x + 15y$.

There are several constraints:
1. Budget constraint: The cost of buying $x$ bottles of perfume at $50 each and $y$ bottles of mascara at $40 each must not exceed $20,000. This gives us $50x + 40y \leq 20,000$.
2. Perfume sales constraint: At least 20 but at most 40 bottles of perfume will be sold, so $20 \leq x \leq 40$.
3. Mascara sales constraint: The number of mascara sold is at most a third the number of perfume sold, which gives us $y \leq \frac{1}{3}x$.

Now, let's translate these into Gurobi code in Python:

```python
from gurobipy import *

# Create a model
m = Model("Makeup_Store_Optimization")

# Decision variables
x = m.addVar(lb=20, ub=40, vtype=GRB.INTEGER, name="Perfume")
y = m.addVar(vtype=GRB.INTEGER, name="Mascara")

# Objective function: Maximize profit
m.setObjective(20*x + 15*y, GRB.MAXIMIZE)

# Constraints
m.addConstr(50*x + 40*y <= 20000, "Budget_Constraint")
m.addConstr(y <= (1/3)*x, "Mascara_Sales_Constraint")

# Solve the model
m.optimize()

# Print solution
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Perfume to buy and sell: {x.x}")
    print(f"Mascara to buy and sell: {y.x}")
    print(f"Maximum profit: ${20*x.x + 15*y.x}")
else:
    print("No optimal solution found")
```