To solve the given optimization problem, we first need to understand the constraints and the objective function. The shop needs to sell at least 15 apple pies and 12 peach pies but can make no more than 20 apple pies and 18 peach pies. Additionally, there's a limit on the total number of pies due to pie crust availability, which is 30 pies in total for both types.

Let's denote:
- \(A\) as the number of apple pies made,
- \(P\) as the number of peach pies made.

The objective function aims to maximize profit. Given that each apple pie brings a profit of $7 and each peach pie brings a profit of $8, we can formulate the objective function as:
\[ \text{Maximize: } 7A + 8P \]

Constraints are:
1. \( A \geq 15 \) (At least 15 apple pies must be made)
2. \( P \geq 12 \) (At least 12 peach pies must be made)
3. \( A \leq 20 \) (No more than 20 apple pies can be made)
4. \( P \leq 18 \) (No more than 18 peach pies can be made)
5. \( A + P \leq 30 \) (Total number of pies cannot exceed 30 due to crust limitations)

We will use Gurobi, a powerful linear and mixed-integer programming solver, in Python to solve this problem.

```python
from gurobipy import *

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

# Define variables
A = m.addVar(vtype=GRB.INTEGER, name="Apple_Pies")
P = m.addVar(vtype=GRB.INTEGER, name="Peach_Pies")

# Set objective function: Maximize profit
m.setObjective(7*A + 8*P, GRB.MAXIMIZE)

# Define constraints
m.addConstr(A >= 15, "Min_Apple_Pies")
m.addConstr(P >= 12, "Min_Peach_Pies")
m.addConstr(A <= 20, "Max_Apple_Pies")
m.addConstr(P <= 18, "Max_Peach_Pies")
m.addConstr(A + P <= 30, "Total_Pie_Crust_Limitation")

# Optimize model
m.optimize()

# Print solution
if m.status == GRB.OPTIMAL:
    print(f"Optimal solution found. Make {A.x} apple pies and {P.x} peach pies.")
else:
    print("No optimal solution found. The model is likely infeasible.")

```
```python
from gurobipy import *

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

# Define variables
A = m.addVar(vtype=GRB.INTEGER, name="Apple_Pies")
P = m.addVar(vtype=GRB.INTEGER, name="Peach_Pies")

# Set objective function: Maximize profit
m.setObjective(7*A + 8*P, GRB.MAXIMIZE)

# Define constraints
m.addConstr(A >= 15, "Min_Apple_Pies")
m.addConstr(P >= 12, "Min_Peach_Pies")
m.addConstr(A <= 20, "Max_Apple_Pies")
m.addConstr(P <= 18, "Max_Peach_Pies")
m.addConstr(A + P <= 30, "Total_Pie_Crust_Limitation")

# Optimize model
m.optimize()

# Print solution
if m.status == GRB.OPTIMAL:
    print(f"Optimal solution found. Make {A.x} apple pies and {P.x} peach pies.")
else:
    print("No optimal solution found. The model is likely infeasible.")

```