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

Let's denote:
- $N$ as the number of neon signs crafted and installed.
- $M$ as the number of metal signs crafted and installed.

The profit per neon sign is $200, and the profit per metal sign is $100. Thus, the total profit can be represented by the objective function: $200N + 100M$.

Each neon sign takes 3 hours for crafting and 2 hours for installation. Each metal sign takes 2 hours for crafting and 1.5 hours for installation. The company has available 950 hours for crafting and 400 hours for installation. These constraints can be represented as follows:
- Crafting time constraint: $3N + 2M \leq 950$
- Installation time constraint: $2N + 1.5M \leq 400$

We also know that the number of signs cannot be negative, so we have non-negativity constraints:
- $N \geq 0$
- $M \geq 0$

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

```python
from gurobipy import *

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

# Define the decision variables
N = m.addVar(lb=0, vtype=GRB.INTEGER, name="Neon_Signs")
M = m.addVar(lb=0, vtype=GRB.INTEGER, name="Metal_Signs")

# Set the objective function: Maximize profit
m.setObjective(200*N + 100*M, GRB.MAXIMIZE)

# Add constraints
m.addConstr(3*N + 2*M <= 950, "Crafting_Time_Constraint")
m.addConstr(2*N + 1.5*M <= 400, "Installation_Time_Constraint")

# Optimize the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print(f"Optimal solution found: {N.varName} = {N.x}, {M.varName} = {M.x}")
    print(f"Maximum profit: ${m.objVal:.2f}")
else:
    print("No optimal solution found")
```