With Prolog, we can often very naturally map such puzzles to programs, or at least to declarative descriptions that can be easily interpreted by Prolog programs.
For instance, in this concrete case, with a suitable operator definition for the operator says, we can write:
:- op(800, xfy, says).
solution([A,B,C,D,E,F,G]) :-
G = salesman,
E = salesman,
C says D = engineer,
A = engineer,
A says B says C says D says E says F says G = engineer.
It is then left to interpret the statements, which we can do for example with: :- use_module(library(dif)).
engineer says Stmt :- false(Stmt).
salesman says Stmt :- true(Stmt).
false(A = B) :- dif(A, B).
false(engineer says Stmt) :- true(Stmt).
false(salesman says Stmt) :- false(Stmt).
true(A = A).
true(engineer says Stmt) :- false(Stmt).
true(salesman says Stmt) :- true(Stmt).
Yielding: ?- solution(S).
S = [engineer,engineer,engineer,salesman,salesman,salesman,salesman]
; S = [engineer,salesman,engineer,salesman,salesman,engineer,salesman]
; S = [engineer,engineer,salesman,engineer,salesman,salesman,salesman]
; S = [engineer,salesman,salesman,engineer,salesman,engineer,salesman]
; false.