To solve this optimization problem, we need to define the decision variables, the objective function, and the constraints. Let's denote the number of kayaks as `k` and the number of canoes as `c`.

The objective is to maximize profit, which can be calculated as $300k + 450c$, since each kayak contributes $300 to the profit and each canoe contributes $450.

There are two main constraints based on the available time for assembly and quality checking:
1. Assembly Time Constraint: The total time used for assembling kayaks and canoes cannot exceed 8000 minutes. Given that each kayak takes 60 minutes of assembly and each canoe takes 80 minutes, this constraint can be represented as $60k + 80c \leq 8000$.
2. Quality Checking Time Constraint: Similarly, the total time used for quality checking kayaks and canoes cannot exceed 4000 minutes. With each kayak requiring 15 minutes of quality checking and each canoe requiring 25 minutes, this constraint is $15k + 25c \leq 4000$.

Additionally, we have non-negativity constraints since the company cannot produce a negative number of kayaks or canoes: $k \geq 0$ and $c \geq 0$.

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

```python
from gurobipy import *

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

# Define the decision variables
k = m.addVar(name="kayaks", lb=0)  # Number of kayaks
c = m.addVar(name="canoes", lb=0)  # Number of canoes

# Objective function: Maximize profit
m.setObjective(300*k + 450*c, GRB.MAXIMIZE)

# Assembly time constraint
m.addConstr(60*k + 80*c <= 8000, name="assembly_time")

# Quality checking time constraint
m.addConstr(15*k + 25*c <= 4000, name="quality_checking_time")

# Optimize the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Number of kayaks: {k.x}")
    print(f"Number of canoes: {c.x}")
    print(f"Maximum profit: ${300*k.x + 450*c.x:.2f}")
else:
    print("No optimal solution found")
```