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

Let's denote:
- $x$ as the number of perfume bottles filled,
- $y$ as the number of cologne bottles filled.

The objective is to maximize profit. Given that each perfume bottle brings in $50 and each cologne bottle brings in $60, the total profit can be represented by the equation: 
\[ \text{Profit} = 50x + 60y \]

There are constraints based on the time required to fill each type of bottle and the minimum quantities that must be filled:
1. Time constraint: Filling a perfume bottle takes 2 minutes, and filling a cologne bottle takes 2.5 minutes. The total available time is 700 minutes. Thus,
\[ 2x + 2.5y \leq 700 \]
2. Minimum perfume bottles constraint:
\[ x \geq 60 \]
3. Minimum cologne bottles constraint:
\[ y \geq 40 \]

Since we cannot fill a negative number of bottles, we also have non-negativity constraints:
\[ x \geq 0 \]
\[ y \geq 0 \]

However, given that $x$ and $y$ must be integers (you can't fill half a bottle), this problem is technically an integer linear programming problem.

Here's how you would set up this problem in Gurobi using Python:

```python
from gurobipy import *

# Create a new model
m = Model("Perfume_Cologne_Problem")

# Define the decision variables
x = m.addVar(vtype=GRB.INTEGER, name="perfume_bottles")
y = m.addVar(vtype=GRB.INTEGER, name="cologne_bottles")

# Set the objective function to maximize profit
m.setObjective(50*x + 60*y, GRB.MAXIMIZE)

# Add constraints
m.addConstr(2*x + 2.5*y <= 700, "time_constraint")
m.addConstr(x >= 60, "min_perfume")
m.addConstr(y >= 40, "min_cologne")

# Optimize the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print(f"Optimal solution: {x.varName} = {x.x}, {y.varName} = {y.x}")
    print(f"Maximum Profit: ${50*x.x + 60*y.x}")
else:
    print("No optimal solution found")
```